1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include <atomic>
9#include <cmath>
10#include "include/core/SkCanvas.h"
11#include "include/core/SkFontLCDConfig.h"
12#include "include/gpu/GrBackendSurface.h"
13#include "src/core/SkAutoPixmapStorage.h"
14#include "src/core/SkImagePriv.h"
15#include "src/image/SkRescaleAndReadPixels.h"
16#include "src/image/SkSurface_Base.h"
17
18static SkPixelGeometry compute_default_geometry() {
19 SkFontLCDConfig::LCDOrder order = SkFontLCDConfig::GetSubpixelOrder();
20 if (SkFontLCDConfig::kNONE_LCDOrder == order) {
21 return kUnknown_SkPixelGeometry;
22 } else {
23 // Bit0 is RGB(0), BGR(1)
24 // Bit1 is H(0), V(1)
25 const SkPixelGeometry gGeo[] = {
26 kRGB_H_SkPixelGeometry,
27 kBGR_H_SkPixelGeometry,
28 kRGB_V_SkPixelGeometry,
29 kBGR_V_SkPixelGeometry,
30 };
31 int index = 0;
32 if (SkFontLCDConfig::kBGR_LCDOrder == order) {
33 index |= 1;
34 }
35 if (SkFontLCDConfig::kVertical_LCDOrientation == SkFontLCDConfig::GetSubpixelOrientation()){
36 index |= 2;
37 }
38 return gGeo[index];
39 }
40}
41
42SkSurfaceProps::SkSurfaceProps() : fFlags(0), fPixelGeometry(kUnknown_SkPixelGeometry) {}
43
44SkSurfaceProps::SkSurfaceProps(InitType) : fFlags(0), fPixelGeometry(compute_default_geometry()) {}
45
46SkSurfaceProps::SkSurfaceProps(uint32_t flags, InitType)
47 : fFlags(flags)
48 , fPixelGeometry(compute_default_geometry())
49{}
50
51SkSurfaceProps::SkSurfaceProps(uint32_t flags, SkPixelGeometry pg)
52 : fFlags(flags), fPixelGeometry(pg)
53{}
54
55SkSurfaceProps::SkSurfaceProps(const SkSurfaceProps&) = default;
56SkSurfaceProps& SkSurfaceProps::operator=(const SkSurfaceProps&) = default;
57
58///////////////////////////////////////////////////////////////////////////////
59
60SkSurface_Base::SkSurface_Base(int width, int height, const SkSurfaceProps* props)
61 : INHERITED(width, height, props) {
62}
63
64SkSurface_Base::SkSurface_Base(const SkImageInfo& info, const SkSurfaceProps* props)
65 : INHERITED(info, props) {
66}
67
68SkSurface_Base::~SkSurface_Base() {
69 // in case the canvas outsurvives us, we null the callback
70 if (fCachedCanvas) {
71 fCachedCanvas->setSurfaceBase(nullptr);
72 }
73}
74
75GrContext* SkSurface_Base::onGetContext_deprecated() {
76 return nullptr;
77}
78
79GrRecordingContext* SkSurface_Base::onGetRecordingContext() {
80 return nullptr;
81}
82
83GrBackendTexture SkSurface_Base::onGetBackendTexture(BackendHandleAccess) {
84 return GrBackendTexture(); // invalid
85}
86
87GrBackendRenderTarget SkSurface_Base::onGetBackendRenderTarget(BackendHandleAccess) {
88 return GrBackendRenderTarget(); // invalid
89}
90
91bool SkSurface_Base::onReplaceBackendTexture(const GrBackendTexture&,
92 GrSurfaceOrigin, ContentChangeMode,
93 TextureReleaseProc,
94 ReleaseContext) {
95 return false;
96}
97
98void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
99 auto image = this->makeImageSnapshot();
100 if (image) {
101 canvas->drawImage(image, x, y, paint);
102 }
103}
104
105void SkSurface_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
106 const SkIRect& origSrcRect,
107 SkSurface::RescaleGamma rescaleGamma,
108 SkFilterQuality rescaleQuality,
109 SkSurface::ReadPixelsCallback callback,
110 SkSurface::ReadPixelsContext context) {
111 SkBitmap src;
112 SkPixmap peek;
113 SkIRect srcRect;
114 if (this->peekPixels(&peek)) {
115 src.installPixels(peek);
116 srcRect = origSrcRect;
117 } else {
118 src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size()));
119 src.allocPixels();
120 if (!this->readPixels(src, origSrcRect.x(), origSrcRect.y())) {
121 callback(context, nullptr);
122 return;
123 }
124 srcRect = SkIRect::MakeSize(src.dimensions());
125 }
126 return SkRescaleAndReadPixels(src, info, srcRect, rescaleGamma, rescaleQuality, callback,
127 context);
128}
129
130void SkSurface_Base::onAsyncRescaleAndReadPixelsYUV420(
131 SkYUVColorSpace yuvColorSpace, sk_sp<SkColorSpace> dstColorSpace, const SkIRect& srcRect,
132 const SkISize& dstSize, RescaleGamma rescaleGamma, SkFilterQuality rescaleQuality,
133 ReadPixelsCallback callback, ReadPixelsContext context) {
134 // TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and
135 // call client's callback.
136 callback(context, nullptr);
137}
138
139bool SkSurface_Base::outstandingImageSnapshot() const {
140 return fCachedImage && !fCachedImage->unique();
141}
142
143void SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
144 this->dirtyGenerationID();
145
146 SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
147
148 if (fCachedImage) {
149 // the surface may need to fork its backend, if its sharing it with
150 // the cached image. Note: we only call if there is an outstanding owner
151 // on the image (besides us).
152 bool unique = fCachedImage->unique();
153 if (!unique) {
154 this->onCopyOnWrite(mode);
155 }
156
157 // regardless of copy-on-write, we must drop our cached image now, so
158 // that the next request will get our new contents.
159 fCachedImage.reset();
160
161 if (unique) {
162 // Our content isn't held by any image now, so we can consider that content mutable.
163 // Raster surfaces need to be told it's safe to consider its pixels mutable again.
164 // We make this call after the ->unref() so the subclass can assert there are no images.
165 this->onRestoreBackingMutability();
166 }
167 } else if (kDiscard_ContentChangeMode == mode) {
168 this->onDiscard();
169 }
170}
171
172uint32_t SkSurface_Base::newGenerationID() {
173 SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
174 static std::atomic<uint32_t> nextID{1};
175 return nextID++;
176}
177
178static SkSurface_Base* asSB(SkSurface* surface) {
179 return static_cast<SkSurface_Base*>(surface);
180}
181
182static const SkSurface_Base* asConstSB(const SkSurface* surface) {
183 return static_cast<const SkSurface_Base*>(surface);
184}
185
186///////////////////////////////////////////////////////////////////////////////
187
188SkSurface::SkSurface(int width, int height, const SkSurfaceProps* props)
189 : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(width), fHeight(height)
190{
191 SkASSERT(fWidth > 0);
192 SkASSERT(fHeight > 0);
193 fGenerationID = 0;
194}
195
196SkSurface::SkSurface(const SkImageInfo& info, const SkSurfaceProps* props)
197 : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(info.width()), fHeight(info.height())
198{
199 SkASSERT(fWidth > 0);
200 SkASSERT(fHeight > 0);
201 fGenerationID = 0;
202}
203
204SkImageInfo SkSurface::imageInfo() {
205 // TODO: do we need to go through canvas for this?
206 return this->getCanvas()->imageInfo();
207}
208
209uint32_t SkSurface::generationID() {
210 if (0 == fGenerationID) {
211 fGenerationID = asSB(this)->newGenerationID();
212 }
213 return fGenerationID;
214}
215
216void SkSurface::notifyContentWillChange(ContentChangeMode mode) {
217 asSB(this)->aboutToDraw(mode);
218}
219
220SkCanvas* SkSurface::getCanvas() {
221 return asSB(this)->getCachedCanvas();
222}
223
224sk_sp<SkImage> SkSurface::makeImageSnapshot() {
225 return asSB(this)->refCachedImage();
226}
227
228sk_sp<SkImage> SkSurface::makeImageSnapshot(const SkIRect& srcBounds) {
229 const SkIRect surfBounds = { 0, 0, fWidth, fHeight };
230 SkIRect bounds = srcBounds;
231 if (!bounds.intersect(surfBounds)) {
232 return nullptr;
233 }
234 SkASSERT(!bounds.isEmpty());
235 if (bounds == surfBounds) {
236 return this->makeImageSnapshot();
237 } else {
238 return asSB(this)->onNewImageSnapshot(&bounds);
239 }
240}
241
242sk_sp<SkSurface> SkSurface::makeSurface(const SkImageInfo& info) {
243 return asSB(this)->onNewSurface(info);
244}
245
246sk_sp<SkSurface> SkSurface::makeSurface(int width, int height) {
247 return this->makeSurface(this->imageInfo().makeWH(width, height));
248}
249
250void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
251 const SkPaint* paint) {
252 return asSB(this)->onDraw(canvas, x, y, paint);
253}
254
255bool SkSurface::peekPixels(SkPixmap* pmap) {
256 return this->getCanvas()->peekPixels(pmap);
257}
258
259bool SkSurface::readPixels(const SkPixmap& pm, int srcX, int srcY) {
260 return this->getCanvas()->readPixels(pm, srcX, srcY);
261}
262
263bool SkSurface::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
264 int srcX, int srcY) {
265 return this->readPixels({dstInfo, dstPixels, dstRowBytes}, srcX, srcY);
266}
267
268bool SkSurface::readPixels(const SkBitmap& bitmap, int srcX, int srcY) {
269 SkPixmap pm;
270 return bitmap.peekPixels(&pm) && this->readPixels(pm, srcX, srcY);
271}
272
273void SkSurface::asyncRescaleAndReadPixels(const SkImageInfo& info,
274 const SkIRect& srcRect,
275 RescaleGamma rescaleGamma,
276 SkFilterQuality rescaleQuality,
277 ReadPixelsCallback callback,
278 ReadPixelsContext context) {
279 if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) ||
280 !SkImageInfoIsValid(info)) {
281 callback(context, nullptr);
282 return;
283 }
284 asSB(this)->onAsyncRescaleAndReadPixels(
285 info, srcRect, rescaleGamma, rescaleQuality, callback, context);
286}
287
288void SkSurface::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
289 sk_sp<SkColorSpace> dstColorSpace,
290 const SkIRect& srcRect,
291 const SkISize& dstSize,
292 RescaleGamma rescaleGamma,
293 SkFilterQuality rescaleQuality,
294 ReadPixelsCallback callback,
295 ReadPixelsContext context) {
296 if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || dstSize.isZero() ||
297 (dstSize.width() & 0b1) || (dstSize.height() & 0b1)) {
298 callback(context, nullptr);
299 return;
300 }
301 asSB(this)->onAsyncRescaleAndReadPixelsYUV420(yuvColorSpace,
302 std::move(dstColorSpace),
303 srcRect,
304 dstSize,
305 rescaleGamma,
306 rescaleQuality,
307 callback,
308 context);
309}
310
311void SkSurface::writePixels(const SkPixmap& pmap, int x, int y) {
312 if (pmap.addr() == nullptr || pmap.width() <= 0 || pmap.height() <= 0) {
313 return;
314 }
315
316 const SkIRect srcR = SkIRect::MakeXYWH(x, y, pmap.width(), pmap.height());
317 const SkIRect dstR = SkIRect::MakeWH(this->width(), this->height());
318 if (SkIRect::Intersects(srcR, dstR)) {
319 ContentChangeMode mode = kRetain_ContentChangeMode;
320 if (srcR.contains(dstR)) {
321 mode = kDiscard_ContentChangeMode;
322 }
323 asSB(this)->aboutToDraw(mode);
324 asSB(this)->onWritePixels(pmap, x, y);
325 }
326}
327
328void SkSurface::writePixels(const SkBitmap& src, int x, int y) {
329 SkPixmap pm;
330 if (src.peekPixels(&pm)) {
331 this->writePixels(pm, x, y);
332 }
333}
334
335GrContext* SkSurface::getContext() {
336 return asSB(this)->onGetContext_deprecated();
337}
338
339GrRecordingContext* SkSurface::recordingContext() {
340 return asSB(this)->onGetRecordingContext();
341}
342
343GrBackendTexture SkSurface::getBackendTexture(BackendHandleAccess access) {
344 return asSB(this)->onGetBackendTexture(access);
345}
346
347GrBackendRenderTarget SkSurface::getBackendRenderTarget(BackendHandleAccess access) {
348 return asSB(this)->onGetBackendRenderTarget(access);
349}
350
351bool SkSurface::replaceBackendTexture(const GrBackendTexture& backendTexture,
352 GrSurfaceOrigin origin, ContentChangeMode mode,
353 TextureReleaseProc textureReleaseProc,
354 ReleaseContext releaseContext) {
355 return asSB(this)->onReplaceBackendTexture(backendTexture, origin, mode, textureReleaseProc,
356 releaseContext);
357}
358
359GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, const GrFlushInfo& flushInfo) {
360 return asSB(this)->onFlush(access, flushInfo, nullptr);
361}
362
363GrSemaphoresSubmitted SkSurface::flush(const GrFlushInfo& info,
364 const GrBackendSurfaceMutableState* newState) {
365 return asSB(this)->onFlush(BackendSurfaceAccess::kNoAccess, info, newState);
366}
367
368bool SkSurface::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores,
369 bool deleteSemaphoresAfterWait) {
370 return asSB(this)->onWait(numSemaphores, waitSemaphores, deleteSemaphoresAfterWait);
371}
372
373bool SkSurface::characterize(SkSurfaceCharacterization* characterization) const {
374 return asConstSB(this)->onCharacterize(characterization);
375}
376
377bool SkSurface::isCompatible(const SkSurfaceCharacterization& characterization) const {
378 return asConstSB(this)->onIsCompatible(characterization);
379}
380
381bool SkSurface::draw(sk_sp<const SkDeferredDisplayList> ddl) {
382 return asSB(this)->onDraw(std::move(ddl));
383}
384
385//////////////////////////////////////////////////////////////////////////////////////
386#include "include/utils/SkNoDrawCanvas.h"
387
388class SkNullSurface : public SkSurface_Base {
389public:
390 SkNullSurface(int width, int height) : SkSurface_Base(width, height, nullptr) {}
391
392protected:
393 SkCanvas* onNewCanvas() override {
394 return new SkNoDrawCanvas(this->width(), this->height());
395 }
396 sk_sp<SkSurface> onNewSurface(const SkImageInfo& info) override {
397 return MakeNull(info.width(), info.height());
398 }
399 sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subsetOrNull) override { return nullptr; }
400 void onWritePixels(const SkPixmap&, int x, int y) override {}
401 void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override {}
402 void onCopyOnWrite(ContentChangeMode) override {}
403};
404
405sk_sp<SkSurface> SkSurface::MakeNull(int width, int height) {
406 if (width < 1 || height < 1) {
407 return nullptr;
408 }
409 return sk_sp<SkSurface>(new SkNullSurface(width, height));
410}
411
412//////////////////////////////////////////////////////////////////////////////////////
413
414#if !SK_SUPPORT_GPU
415
416sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext*, SkBudgeted, const SkImageInfo&,
417 int, GrSurfaceOrigin, const SkSurfaceProps*, bool) {
418 return nullptr;
419}
420
421sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext*, const SkSurfaceCharacterization&,
422 SkBudgeted) {
423 return nullptr;
424}
425
426sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext*, const GrBackendTexture&,
427 GrSurfaceOrigin origin, int sampleCnt,
428 SkColorType, sk_sp<SkColorSpace>,
429 const SkSurfaceProps*,
430 TextureReleaseProc, ReleaseContext) {
431 return nullptr;
432}
433
434sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext*,
435 const GrBackendRenderTarget&,
436 GrSurfaceOrigin origin,
437 SkColorType,
438 sk_sp<SkColorSpace>,
439 const SkSurfaceProps*,
440 RenderTargetReleaseProc, ReleaseContext) {
441 return nullptr;
442}
443
444void SkSurface::flushAndSubmit() {
445 this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo());
446}
447
448#endif
449