1 /*
2 * Copyright 2008 The Android Open Source Project
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 "include/core/SkCanvas.h"
9
10 #include "include/core/SkBlender.h"
11 #include "include/core/SkColorFilter.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkImageFilter.h"
14 #include "include/core/SkLog.h"
15 #include "include/core/SkPathEffect.h"
16 #include "include/core/SkPicture.h"
17 #include "include/core/SkRRect.h"
18 #include "include/core/SkRasterHandleAllocator.h"
19 #include "include/core/SkString.h"
20 #include "include/core/SkTextBlob.h"
21 #include "include/core/SkVertices.h"
22 #include "include/effects/SkRuntimeEffect.h"
23 #include "include/private/SkTOptional.h"
24 #include "include/private/SkTo.h"
25 #include "include/utils/SkNoDrawCanvas.h"
26 #include "src/core/SkArenaAlloc.h"
27 #include "src/core/SkBitmapDevice.h"
28 #include "src/core/SkCanvasPriv.h"
29 #include "src/core/SkClipStack.h"
30 #include "src/core/SkColorFilterBase.h"
31 #include "src/core/SkDraw.h"
32 #include "src/core/SkGlyphRun.h"
33 #include "src/core/SkImageFilterCache.h"
34 #include "src/core/SkImageFilter_Base.h"
35 #include "src/core/SkLatticeIter.h"
36 #include "src/core/SkMSAN.h"
37 #include "src/core/SkMarkerStack.h"
38 #include "src/core/SkMatrixPriv.h"
39 #include "src/core/SkMatrixUtils.h"
40 #include "src/core/SkPaintPriv.h"
41 #include "src/core/SkRasterClip.h"
42 #include "src/core/SkSpecialImage.h"
43 #include "src/core/SkStrikeCache.h"
44 #include "src/core/SkTLazy.h"
45 #include "src/core/SkTextFormatParams.h"
46 #include "src/core/SkTraceEvent.h"
47 #include "src/core/SkVerticesPriv.h"
48 #include "src/image/SkImage_Base.h"
49 #include "src/image/SkSurface_Base.h"
50 #include "src/utils/SkPatchUtils.h"
51
52 #include <memory>
53 #include <new>
54
55 #ifdef SK_ENABLE_PATH_COMPLEXITY_DFX
56 #include "src/core/SkPathComplexityDfx.h"
57 #endif
58
59 #if SK_SUPPORT_GPU
60 #include "include/gpu/GrDirectContext.h"
61 #include "src/gpu/BaseDevice.h"
62 #include "src/gpu/SkGr.h"
63 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
64 # include "src/gpu/GrRenderTarget.h"
65 # include "src/gpu/GrRenderTargetProxy.h"
66 #endif
67 #endif
68
69 #define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
70 #define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
71
72 // This is a test: static_assert with no message is a c++17 feature,
73 // and std::max() is constexpr only since the c++14 stdlib.
74 static_assert(std::max(3,4) == 4);
75
76 ///////////////////////////////////////////////////////////////////////////////////////////////////
77
78 /*
79 * Return true if the drawing this rect would hit every pixels in the canvas.
80 *
81 * Returns false if
82 * - rect does not contain the canvas' bounds
83 * - paint is not fill
84 * - paint would blur or otherwise change the coverage of the rect
85 */
wouldOverwriteEntireSurface(const SkRect * rect,const SkPaint * paint,ShaderOverrideOpacity overrideOpacity) const86 bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
87 ShaderOverrideOpacity overrideOpacity) const {
88 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
89 (int)kNone_ShaderOverrideOpacity,
90 "need_matching_enums0");
91 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
92 (int)kOpaque_ShaderOverrideOpacity,
93 "need_matching_enums1");
94 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
95 (int)kNotOpaque_ShaderOverrideOpacity,
96 "need_matching_enums2");
97
98 const SkISize size = this->getBaseLayerSize();
99 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
100
101 // if we're clipped at all, we can't overwrite the entire surface
102 {
103 const SkBaseDevice* base = this->baseDevice();
104 const SkBaseDevice* top = this->topDevice();
105 if (base != top) {
106 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
107 }
108 if (!base->clipIsWideOpen()) {
109 return false;
110 }
111 }
112
113 if (rect) {
114 if (!this->getTotalMatrix().isScaleTranslate()) {
115 return false; // conservative
116 }
117
118 SkRect devRect;
119 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
120 if (!devRect.contains(bounds)) {
121 return false;
122 }
123 }
124
125 if (paint) {
126 SkPaint::Style paintStyle = paint->getStyle();
127 if (!(paintStyle == SkPaint::kFill_Style ||
128 paintStyle == SkPaint::kStrokeAndFill_Style)) {
129 return false;
130 }
131 if (paint->getMaskFilter() || paint->getPathEffect() || paint->getImageFilter()) {
132 return false; // conservative
133 }
134 }
135 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
136 }
137
138 ///////////////////////////////////////////////////////////////////////////////////////////////////
139
140 // experimental for faster tiled drawing...
141 //#define SK_TRACE_SAVERESTORE
142
143 #ifdef SK_TRACE_SAVERESTORE
144 static int gLayerCounter;
inc_layer()145 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
dec_layer()146 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
147
148 static int gRecCounter;
inc_rec()149 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
dec_rec()150 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
151
152 static int gCanvasCounter;
inc_canvas()153 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
dec_canvas()154 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
155 #else
156 #define inc_layer()
157 #define dec_layer()
158 #define inc_rec()
159 #define dec_rec()
160 #define inc_canvas()
161 #define dec_canvas()
162 #endif
163
predrawNotify(bool willOverwritesEntireSurface)164 bool SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
165 if (fSurfaceBase) {
166 if (!fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
167 ? SkSurface::kDiscard_ContentChangeMode
168 : SkSurface::kRetain_ContentChangeMode)) {
169 return false;
170 }
171 }
172 return true;
173 }
174
predrawNotify(const SkRect * rect,const SkPaint * paint,ShaderOverrideOpacity overrideOpacity)175 bool SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
176 ShaderOverrideOpacity overrideOpacity) {
177 if (fSurfaceBase) {
178 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
179 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
180 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
181 // and therefore we don't care which mode we're in.
182 //
183 if (fSurfaceBase->outstandingImageSnapshot()) {
184 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
185 mode = SkSurface::kDiscard_ContentChangeMode;
186 }
187 }
188 if (!fSurfaceBase->aboutToDraw(mode)) {
189 return false;
190 }
191 }
192 return true;
193 }
194
195 ///////////////////////////////////////////////////////////////////////////////
196
Layer(sk_sp<SkBaseDevice> device,sk_sp<SkImageFilter> imageFilter,const SkPaint & paint)197 SkCanvas::Layer::Layer(sk_sp<SkBaseDevice> device,
198 sk_sp<SkImageFilter> imageFilter,
199 const SkPaint& paint)
200 : fDevice(std::move(device))
201 , fImageFilter(std::move(imageFilter))
202 , fPaint(paint)
203 , fDiscard(false) {
204 SkASSERT(fDevice);
205 // Any image filter should have been pulled out and stored in 'imageFilter' so that 'paint'
206 // can be used as-is to draw the result of the filter to the dst device.
207 SkASSERT(!fPaint.getImageFilter());
208 }
209
MCRec(SkBaseDevice * device)210 SkCanvas::MCRec::MCRec(SkBaseDevice* device) : fDevice(device) {
211 SkASSERT(fDevice);
212 inc_rec();
213 }
214
MCRec(const MCRec * prev)215 SkCanvas::MCRec::MCRec(const MCRec* prev) : fDevice(prev->fDevice), fMatrix(prev->fMatrix) {
216 SkASSERT(fDevice);
217 inc_rec();
218 }
219
~MCRec()220 SK_ALWAYS_INLINE SkCanvas::MCRec::~MCRec() { dec_rec(); }
221
newLayer(sk_sp<SkBaseDevice> layerDevice,sk_sp<SkImageFilter> filter,const SkPaint & restorePaint)222 void SkCanvas::MCRec::newLayer(sk_sp<SkBaseDevice> layerDevice,
223 sk_sp<SkImageFilter> filter,
224 const SkPaint& restorePaint) {
225 SkASSERT(!fBackImage);
226 fLayer = std::make_unique<Layer>(std::move(layerDevice), std::move(filter), restorePaint);
227 fDevice = fLayer->fDevice.get();
228 }
229
reset(SkBaseDevice * device)230 void SkCanvas::MCRec::reset(SkBaseDevice* device) {
231 SkASSERT(!fLayer);
232 SkASSERT(device);
233 SkASSERT(fDeferredSaveCount == 0);
234 fDevice = device;
235 fMatrix.setIdentity();
236 }
237
238 class SkCanvas::AutoUpdateQRBounds {
239 public:
AutoUpdateQRBounds(SkCanvas * canvas)240 explicit AutoUpdateQRBounds(SkCanvas* canvas) : fCanvas(canvas) {
241 // pre-condition, fQuickRejectBounds and other state should be valid before anything
242 // modifies the device's clip.
243 fCanvas->validateClip();
244 }
~AutoUpdateQRBounds()245 ~AutoUpdateQRBounds() {
246 fCanvas->fQuickRejectBounds = fCanvas->computeDeviceClipBounds();
247 // post-condition, we should remain valid after re-computing the bounds
248 fCanvas->validateClip();
249 }
250
251 private:
252 SkCanvas* fCanvas;
253
254 AutoUpdateQRBounds(AutoUpdateQRBounds&&) = delete;
255 AutoUpdateQRBounds(const AutoUpdateQRBounds&) = delete;
256 AutoUpdateQRBounds& operator=(AutoUpdateQRBounds&&) = delete;
257 AutoUpdateQRBounds& operator=(const AutoUpdateQRBounds&) = delete;
258 };
259
260 /////////////////////////////////////////////////////////////////////////////
261 // Attempts to convert an image filter to its equivalent color filter, which if possible, modifies
262 // the paint to compose the image filter's color filter into the paint's color filter slot.
263 // Returns true if the paint has been modified.
264 // Requires the paint to have an image filter and the copy-on-write be initialized.
image_to_color_filter(SkPaint * paint)265 static bool image_to_color_filter(SkPaint* paint) {
266 SkASSERT(SkToBool(paint) && paint->getImageFilter());
267
268 SkColorFilter* imgCFPtr;
269 if (!paint->getImageFilter()->asAColorFilter(&imgCFPtr)) {
270 return false;
271 }
272 sk_sp<SkColorFilter> imgCF(imgCFPtr);
273
274 SkColorFilter* paintCF = paint->getColorFilter();
275 if (paintCF) {
276 // The paint has both a colorfilter(paintCF) and an imagefilter-that-is-a-colorfilter(imgCF)
277 // and we need to combine them into a single colorfilter.
278 imgCF = imgCF->makeComposed(sk_ref_sp(paintCF));
279 }
280
281 paint->setColorFilter(std::move(imgCF));
282 paint->setImageFilter(nullptr);
283 return true;
284 }
285
286 /**
287 * We implement ImageFilters for a given draw by creating a layer, then applying the
288 * imagefilter to the pixels of that layer (its backing surface/image), and then
289 * we call restore() to xfer that layer to the main canvas.
290 *
291 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
292 * 2. Generate the src pixels:
293 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
294 * return (fPaint). We then draw the primitive (using srcover) into a cleared
295 * buffer/surface.
296 * 3. Restore the layer created in #1
297 * The imagefilter is passed the buffer/surface from the layer (now filled with the
298 * src pixels of the primitive). It returns a new "filtered" buffer, which we
299 * draw onto the previous layer using the xfermode from the original paint.
300 */
301 class AutoLayerForImageFilter {
302 public:
303 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
304 // paint. It's used to determine the size of the offscreen layer for filters.
305 // If null, the clip will be used instead.
306 //
307 // Draw functions should use layer->paint() instead of the passed-in paint.
AutoLayerForImageFilter(SkCanvas * canvas,const SkPaint & paint,const SkRect * rawBounds=nullptr)308 AutoLayerForImageFilter(SkCanvas* canvas,
309 const SkPaint& paint,
310 const SkRect* rawBounds = nullptr)
311 : fPaint(paint)
312 , fCanvas(canvas)
313 , fTempLayerForImageFilter(false) {
314 SkDEBUGCODE(fSaveCount = canvas->getSaveCount();)
315
316 if (fPaint.getImageFilter() && !image_to_color_filter(&fPaint)) {
317 // The draw paint has an image filter that couldn't be simplified to an equivalent
318 // color filter, so we have to inject an automatic saveLayer().
319 SkPaint restorePaint;
320 restorePaint.setImageFilter(fPaint.refImageFilter());
321 restorePaint.setBlender(fPaint.refBlender());
322
323 // Remove the restorePaint fields from our "working" paint
324 fPaint.setImageFilter(nullptr);
325 fPaint.setBlendMode(SkBlendMode::kSrcOver);
326
327 SkRect storage;
328 if (rawBounds && fPaint.canComputeFastBounds()) {
329 // Make rawBounds include all paint outsets except for those due to image filters.
330 // At this point, fPaint's image filter has been moved to 'restorePaint'.
331 SkASSERT(!fPaint.getImageFilter());
332 rawBounds = &fPaint.computeFastBounds(*rawBounds, &storage);
333 }
334
335 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &restorePaint),
336 SkCanvas::kFullLayer_SaveLayerStrategy);
337 fTempLayerForImageFilter = true;
338 }
339 }
340
341 AutoLayerForImageFilter(const AutoLayerForImageFilter&) = delete;
342 AutoLayerForImageFilter& operator=(const AutoLayerForImageFilter&) = delete;
343 AutoLayerForImageFilter(AutoLayerForImageFilter&&) = default;
344 AutoLayerForImageFilter& operator=(AutoLayerForImageFilter&&) = default;
345
~AutoLayerForImageFilter()346 ~AutoLayerForImageFilter() {
347 if (fTempLayerForImageFilter) {
348 fCanvas->internalRestore();
349 }
350 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
351 }
352
paint() const353 const SkPaint& paint() const { return fPaint; }
354
355 private:
356 SkPaint fPaint;
357 SkCanvas* fCanvas;
358 bool fTempLayerForImageFilter;
359
360 SkDEBUGCODE(int fSaveCount;)
361 };
362
aboutToDraw(SkCanvas * canvas,const SkPaint & paint,const SkRect * rawBounds,CheckForOverwrite checkOverwrite,ShaderOverrideOpacity overrideOpacity)363 skstd::optional<AutoLayerForImageFilter> SkCanvas::aboutToDraw(
364 SkCanvas* canvas,
365 const SkPaint& paint,
366 const SkRect* rawBounds,
367 CheckForOverwrite checkOverwrite,
368 ShaderOverrideOpacity overrideOpacity)
369 {
370 if (checkOverwrite == CheckForOverwrite::kYes) {
371 if (!this->predrawNotify(rawBounds, &paint, overrideOpacity)) {
372 return skstd::nullopt;
373 }
374 } else {
375 if (!this->predrawNotify()) {
376 return skstd::nullopt;
377 }
378 }
379 return skstd::optional<AutoLayerForImageFilter>(canvas, paint, rawBounds);
380 }
381
382 ////////////////////////////////////////////////////////////////////////////
383
resetForNextPicture(const SkIRect & bounds)384 void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
385 this->restoreToCount(1);
386
387 // We're peering through a lot of structs here. Only at this scope do we
388 // know that the device is a SkNoPixelsDevice.
389 SkASSERT(fBaseDevice->isNoPixelsDevice());
390 static_cast<SkNoPixelsDevice*>(fBaseDevice.get())->resetForNextPicture(bounds);
391 fMCRec->reset(fBaseDevice.get());
392 fQuickRejectBounds = this->computeDeviceClipBounds();
393 }
394
init(sk_sp<SkBaseDevice> device)395 void SkCanvas::init(sk_sp<SkBaseDevice> device) {
396 // SkCanvas.h declares internal storage for the hidden struct MCRec, and this
397 // assert ensure it's sufficient. <= is used because the struct has pointer fields, so the
398 // declared size is an upper bound across architectures. When the size is smaller, more stack
399 static_assert(sizeof(MCRec) <= kMCRecSize);
400
401 if (!device) {
402 device = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeEmpty(), fProps);
403 }
404
405 // From this point on, SkCanvas will always have a device
406 SkASSERT(device);
407
408 fSaveCount = 1;
409 fMCRec = new (fMCStack.push_back()) MCRec(device.get());
410 fMarkerStack = sk_make_sp<SkMarkerStack>();
411
412 // The root device and the canvas should always have the same pixel geometry
413 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
414 device->setMarkerStack(fMarkerStack.get());
415
416 fSurfaceBase = nullptr;
417 fBaseDevice = std::move(device);
418 fScratchGlyphRunBuilder = std::make_unique<SkGlyphRunBuilder>();
419 fQuickRejectBounds = this->computeDeviceClipBounds();
420 }
421
SkCanvas()422 SkCanvas::SkCanvas() : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
423 inc_canvas();
424 this->init(nullptr);
425 }
426
SkCanvas(int width,int height,const SkSurfaceProps * props)427 SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
428 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
429 , fProps(SkSurfacePropsCopyOrDefault(props)) {
430 inc_canvas();
431 this->init(sk_make_sp<SkNoPixelsDevice>(
432 SkIRect::MakeWH(std::max(width, 0), std::max(height, 0)), fProps));
433 }
434
SkCanvas(const SkIRect & bounds)435 SkCanvas::SkCanvas(const SkIRect& bounds)
436 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
437 inc_canvas();
438
439 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
440 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
441 }
442
SkCanvas(sk_sp<SkBaseDevice> device)443 SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
444 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
445 , fProps(device->surfaceProps()) {
446 inc_canvas();
447
448 this->init(device);
449 }
450
SkCanvas(const SkBitmap & bitmap,const SkSurfaceProps & props)451 SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
452 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), fProps(props) {
453 inc_canvas();
454
455 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
456 this->init(device);
457 }
458
SkCanvas(const SkBitmap & bitmap,std::unique_ptr<SkRasterHandleAllocator> alloc,SkRasterHandleAllocator::Handle hndl)459 SkCanvas::SkCanvas(const SkBitmap& bitmap,
460 std::unique_ptr<SkRasterHandleAllocator> alloc,
461 SkRasterHandleAllocator::Handle hndl)
462 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
463 , fAllocator(std::move(alloc)) {
464 inc_canvas();
465
466 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
467 this->init(device);
468 }
469
SkCanvas(const SkBitmap & bitmap)470 SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
471
472 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
SkCanvas(const SkBitmap & bitmap,ColorBehavior)473 SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
474 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
475 inc_canvas();
476
477 SkBitmap tmp(bitmap);
478 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
479 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
480 this->init(device);
481 }
482 #endif
483
~SkCanvas()484 SkCanvas::~SkCanvas() {
485 // Mark all pending layers to be discarded during restore (rather than drawn)
486 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
487 for (;;) {
488 MCRec* rec = (MCRec*)iter.next();
489 if (!rec) {
490 break;
491 }
492 if (rec->fLayer) {
493 rec->fLayer->fDiscard = true;
494 }
495 }
496
497 // free up the contents of our deque
498 this->restoreToCount(1); // restore everything but the last
499 this->internalRestore(); // restore the last, since we're going away
500
501 dec_canvas();
502 }
503
504 ///////////////////////////////////////////////////////////////////////////////
505
flush()506 void SkCanvas::flush() {
507 this->onFlush();
508 }
509
onFlush()510 void SkCanvas::onFlush() {
511 #if SK_SUPPORT_GPU
512 auto dContext = GrAsDirectContext(this->recordingContext());
513
514 if (dContext) {
515 dContext->flushAndSubmit();
516 }
517 #endif
518 }
519
getSurface() const520 SkSurface* SkCanvas::getSurface() const {
521 return fSurfaceBase;
522 }
523
getBaseLayerSize() const524 SkISize SkCanvas::getBaseLayerSize() const {
525 return this->baseDevice()->imageInfo().dimensions();
526 }
527
topDevice() const528 SkBaseDevice* SkCanvas::topDevice() const {
529 SkASSERT(fMCRec->fDevice);
530 return fMCRec->fDevice;
531 }
532
readPixels(const SkPixmap & pm,int x,int y)533 bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
534 return pm.addr() && this->baseDevice()->readPixels(pm, x, y);
535 }
536
readPixels(const SkImageInfo & dstInfo,void * dstP,size_t rowBytes,int x,int y)537 bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
538 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
539 }
540
readPixels(const SkBitmap & bm,int x,int y)541 bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
542 SkPixmap pm;
543 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
544 }
545
writePixels(const SkBitmap & bitmap,int x,int y)546 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
547 SkPixmap pm;
548 if (bitmap.peekPixels(&pm)) {
549 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
550 }
551 return false;
552 }
553
writePixels(const SkImageInfo & srcInfo,const void * pixels,size_t rowBytes,int x,int y)554 bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
555 int x, int y) {
556 SkBaseDevice* device = this->baseDevice();
557
558 // This check gives us an early out and prevents generation ID churn on the surface.
559 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
560 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
561 if (!srcRect.intersect({0, 0, device->width(), device->height()})) {
562 return false;
563 }
564
565 // Tell our owning surface to bump its generation ID.
566 const bool completeOverwrite = srcRect.size() == device->imageInfo().dimensions();
567 if (!this->predrawNotify(completeOverwrite)) {
568 return false;
569 }
570
571 // This can still fail, most notably in the case of a invalid color type or alpha type
572 // conversion. We could pull those checks into this function and avoid the unnecessary
573 // generation ID bump. But then we would be performing those checks twice, since they
574 // are also necessary at the bitmap/pixmap entry points.
575 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
576 }
577
578 //////////////////////////////////////////////////////////////////////////////
579
checkForDeferredSave()580 void SkCanvas::checkForDeferredSave() {
581 if (fMCRec->fDeferredSaveCount > 0) {
582 this->doSave();
583 }
584 }
585
getSaveCount() const586 int SkCanvas::getSaveCount() const {
587 #ifdef SK_DEBUG
588 int count = 0;
589 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
590 for (;;) {
591 const MCRec* rec = (const MCRec*)iter.next();
592 if (!rec) {
593 break;
594 }
595 count += 1 + rec->fDeferredSaveCount;
596 }
597 SkASSERT(count == fSaveCount);
598 #endif
599 return fSaveCount;
600 }
601
save()602 int SkCanvas::save() {
603 fSaveCount += 1;
604 fMCRec->fDeferredSaveCount += 1;
605 return this->getSaveCount() - 1; // return our prev value
606 }
607
doSave()608 void SkCanvas::doSave() {
609 this->willSave();
610
611 SkASSERT(fMCRec->fDeferredSaveCount > 0);
612 fMCRec->fDeferredSaveCount -= 1;
613 this->internalSave();
614 }
615
restore()616 void SkCanvas::restore() {
617 if (fMCRec->fDeferredSaveCount > 0) {
618 SkASSERT(fSaveCount > 1);
619 fSaveCount -= 1;
620 fMCRec->fDeferredSaveCount -= 1;
621 } else {
622 // check for underflow
623 if (fMCStack.count() > 1) {
624 this->willRestore();
625 SkASSERT(fSaveCount > 1);
626 fSaveCount -= 1;
627 this->internalRestore();
628 this->didRestore();
629 }
630 }
631 }
632
restoreToCount(int count)633 void SkCanvas::restoreToCount(int count) {
634 // safety check
635 if (count < 1) {
636 count = 1;
637 }
638
639 int n = this->getSaveCount() - count;
640 for (int i = 0; i < n; ++i) {
641 this->restore();
642 }
643 }
644
internalSave()645 void SkCanvas::internalSave() {
646 fMCRec = new (fMCStack.push_back()) MCRec(fMCRec);
647
648 this->topDevice()->save();
649 }
650
saveLayer(const SkRect * bounds,const SkPaint * paint)651 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
652 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
653 }
654
saveLayer(const SaveLayerRec & rec)655 int SkCanvas::saveLayer(const SaveLayerRec& rec) {
656 TRACE_EVENT0("skia", TRACE_FUNC);
657 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
658 // no need for the layer (or any of the draws until the matching restore()
659 this->save();
660 this->clipRect({0,0,0,0});
661 } else {
662 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
663 fSaveCount += 1;
664 this->internalSaveLayer(rec, strategy);
665 }
666 return this->getSaveCount() - 1;
667 }
668
only_axis_aligned_saveBehind(const SkRect * bounds)669 int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
670 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
671 // Assuming clips never expand, if the request bounds is outside of the current clip
672 // there is no need to copy/restore the area, so just devolve back to a regular save.
673 this->save();
674 } else {
675 bool doTheWork = this->onDoSaveBehind(bounds);
676 fSaveCount += 1;
677 this->internalSave();
678 if (doTheWork) {
679 this->internalSaveBehind(bounds);
680 }
681 }
682 return this->getSaveCount() - 1;
683 }
684
685 // In our current design/features, we should never have a layer (src) in a different colorspace
686 // than its parent (dst), so we assert that here. This is called out from other asserts, in case
687 // we add some feature in the future to allow a given layer/imagefilter to operate in a specific
688 // colorspace.
check_drawdevice_colorspaces(SkColorSpace * src,SkColorSpace * dst)689 static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
690 SkASSERT(src == dst);
691 }
692
693 // Helper function to compute the center reference point used for scale decomposition under
694 // non-linear transformations.
compute_decomposition_center(const SkMatrix & dstToLocal,const skif::ParameterSpace<SkRect> * contentBounds,const skif::DeviceSpace<SkIRect> & targetOutput)695 static skif::ParameterSpace<SkPoint> compute_decomposition_center(
696 const SkMatrix& dstToLocal,
697 const skif::ParameterSpace<SkRect>* contentBounds,
698 const skif::DeviceSpace<SkIRect>& targetOutput) {
699 // Will use the inverse and center of the device bounds if the content bounds aren't provided.
700 SkRect rect = contentBounds ? SkRect(*contentBounds) : SkRect::Make(SkIRect(targetOutput));
701 SkPoint center = {rect.centerX(), rect.centerY()};
702 if (!contentBounds) {
703 // Theoretically, the inverse transform could put center's homogeneous coord behind W = 0,
704 // but that case is handled automatically in Mapping::decomposeCTM later.
705 dstToLocal.mapPoints(¢er, 1);
706 }
707
708 return skif::ParameterSpace<SkPoint>(center);
709 }
710
711 // Compute suitable transformations and layer bounds for a new layer that will be used as the source
712 // input into 'filter' before being drawn into 'dst' via the returned skif::Mapping.
713 // Null filters are permitted and act as the identity. The returned mapping will be compatible with
714 // the image filter.
715 //
716 // Returns an empty rect if the layer wouldn't draw anything after filtering.
get_layer_mapping_and_bounds(const SkImageFilter * filter,const SkMatrix & localToDst,const skif::DeviceSpace<SkIRect> & targetOutput,const skif::ParameterSpace<SkRect> * contentBounds=nullptr,bool mustCoverDst=true,SkScalar scaleFactor=1.0f)717 static std::pair<skif::Mapping, skif::LayerSpace<SkIRect>> get_layer_mapping_and_bounds(
718 const SkImageFilter* filter,
719 const SkMatrix& localToDst,
720 const skif::DeviceSpace<SkIRect>& targetOutput,
721 const skif::ParameterSpace<SkRect>* contentBounds = nullptr,
722 bool mustCoverDst = true,
723 SkScalar scaleFactor = 1.0f) {
724 auto failedMapping = []() {
725 return std::make_pair<skif::Mapping, skif::LayerSpace<SkIRect>>(
726 {}, skif::LayerSpace<SkIRect>::Empty());
727 };
728
729 SkMatrix dstToLocal;
730 if (!localToDst.isFinite() ||
731 !localToDst.invert(&dstToLocal)) {
732 return failedMapping();
733 }
734
735 skif::ParameterSpace<SkPoint> center =
736 compute_decomposition_center(dstToLocal, contentBounds, targetOutput);
737 // *after* possibly getting a representative point from the provided content bounds, it might
738 // be necessary to discard the bounds for subsequent layer calculations.
739 if (mustCoverDst) {
740 contentBounds = nullptr;
741 }
742
743 // Determine initial mapping and a reasonable maximum dimension to prevent layer-to-device
744 // transforms with perspective and skew from triggering excessive buffer allocations.
745 skif::Mapping mapping;
746 if (!mapping.decomposeCTM(localToDst, filter, center)) {
747 return failedMapping();
748 }
749 // Push scale factor into layer matrix and device matrix (net no change, but the layer will have
750 // its resolution adjusted in comparison to the final device).
751 if (scaleFactor != 1.0f &&
752 !mapping.adjustLayerSpace(SkMatrix::Scale(scaleFactor, scaleFactor))) {
753 return failedMapping();
754 }
755
756 // Perspective and skew could exceed this since mapping.deviceToLayer(targetOutput) is
757 // theoretically unbounded under those conditions. Under a 45 degree rotation, a layer needs to
758 // be 2X larger per side of the prior device in order to fully cover it. We use the max of that
759 // and 2048 for a reasonable upper limit (this allows small layers under extreme transforms to
760 // use more relative resolution than a larger layer).
761 static const int kMinDimThreshold = 2048;
762 int maxLayerDim = std::max(Sk64_pin_to_s32(2 * std::max(SkIRect(targetOutput).width64(),
763 SkIRect(targetOutput).height64())),
764 kMinDimThreshold);
765
766 skif::LayerSpace<SkIRect> layerBounds;
767 if (filter) {
768 layerBounds = as_IFB(filter)->getInputBounds(mapping, targetOutput, contentBounds);
769 // When a filter is involved, the layer size may be larger than the default maxLayerDim due
770 // to required inputs for filters (e.g. a displacement map with a large radius).
771 if (layerBounds.width() > maxLayerDim || layerBounds.height() > maxLayerDim) {
772 skif::Mapping idealMapping(SkMatrix::I(), mapping.layerMatrix());
773 auto idealLayerBounds = as_IFB(filter)->getInputBounds(idealMapping, targetOutput,
774 contentBounds);
775 maxLayerDim = std::max(std::max(idealLayerBounds.width(), idealLayerBounds.height()),
776 maxLayerDim);
777 }
778 } else {
779 layerBounds = mapping.deviceToLayer(targetOutput);
780 if (contentBounds) {
781 // For better or for worse, user bounds currently act as a hard clip on the layer's
782 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
783 skif::LayerSpace<SkIRect> knownBounds = mapping.paramToLayer(*contentBounds).roundOut();
784 if (!layerBounds.intersect(knownBounds)) {
785 return failedMapping();
786 }
787 }
788 }
789
790 if (layerBounds.width() > maxLayerDim || layerBounds.height() > maxLayerDim) {
791 skif::LayerSpace<SkIRect> newLayerBounds(
792 SkIRect::MakeWH(std::min(layerBounds.width(), maxLayerDim),
793 std::min(layerBounds.height(), maxLayerDim)));
794 SkMatrix adjust = SkMatrix::MakeRectToRect(SkRect::Make(SkIRect(layerBounds)),
795 SkRect::Make(SkIRect(newLayerBounds)),
796 SkMatrix::kFill_ScaleToFit);
797 if (!mapping.adjustLayerSpace(adjust)) {
798 return failedMapping();
799 } else {
800 layerBounds = newLayerBounds;
801 }
802 }
803
804 return {mapping, layerBounds};
805 }
806
make_layer_info(const SkImageInfo & prev,int w,int h,bool f16)807 static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool f16) {
808 SkColorType ct = f16 ? SkColorType::kRGBA_F16_SkColorType : prev.colorType();
809 if (!f16 &&
810 prev.bytesPerPixel() <= 4 &&
811 prev.colorType() != kRGBA_8888_SkColorType &&
812 prev.colorType() != kBGRA_8888_SkColorType) {
813 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
814 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
815 ct = kN32_SkColorType;
816 }
817 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
818 }
819
draw_layer_as_sprite(const SkMatrix & matrix,const SkISize & size)820 static bool draw_layer_as_sprite(const SkMatrix& matrix, const SkISize& size) {
821 // Assume anti-aliasing and highest valid filter mode (linear) for drawing layers and image
822 // filters. If the layer can be drawn as a sprite, these can be downgraded.
823 SkPaint paint;
824 paint.setAntiAlias(true);
825 SkSamplingOptions sampling{SkFilterMode::kLinear};
826 return SkTreatAsSprite(matrix, size, sampling, paint);
827 }
828
internalDrawDeviceWithFilter(SkBaseDevice * src,SkBaseDevice * dst,const SkImageFilter * filter,const SkPaint & paint,DeviceCompatibleWithFilter compat,SkScalar scaleFactor)829 void SkCanvas::internalDrawDeviceWithFilter(SkBaseDevice* src,
830 SkBaseDevice* dst,
831 const SkImageFilter* filter,
832 const SkPaint& paint,
833 DeviceCompatibleWithFilter compat,
834 SkScalar scaleFactor) {
835 check_drawdevice_colorspaces(dst->imageInfo().colorSpace(),
836 src->imageInfo().colorSpace());
837
838 // 'filter' sees the src device's buffer as the implicit input image, and processes the image
839 // in this device space (referred to as the "layer" space). However, the filter
840 // parameters need to respect the current matrix, which is not necessarily the local matrix that
841 // was set on 'src' (e.g. because we've popped src off the stack already).
842 // TODO (michaelludwig): Stay in SkM44 once skif::Mapping supports SkM44 instead of SkMatrix.
843 SkMatrix localToSrc = (src->globalToDevice() * fMCRec->fMatrix).asM33();
844 SkISize srcDims = src->imageInfo().dimensions();
845
846 // Whether or not we need to make a transformed tmp image from 'src', and what that transform is
847 bool needsIntermediateImage = false;
848 SkMatrix srcToIntermediate;
849
850 skif::Mapping mapping;
851 skif::LayerSpace<SkIRect> requiredInput;
852 if (compat == DeviceCompatibleWithFilter::kYes) {
853 // Just use the relative transform from src to dst and the src's whole image, since
854 // internalSaveLayer should have already determined what was necessary.
855 SkASSERT(scaleFactor == 1.0f);
856 mapping = skif::Mapping(src->getRelativeTransform(*dst), localToSrc);
857 requiredInput = skif::LayerSpace<SkIRect>(SkIRect::MakeSize(srcDims));
858 SkASSERT(!requiredInput.isEmpty());
859 } else {
860 // Compute the image filter mapping by decomposing the local->device matrix of dst and
861 // re-determining the required input.
862 std::tie(mapping, requiredInput) = get_layer_mapping_and_bounds(
863 filter, dst->localToDevice(), skif::DeviceSpace<SkIRect>(dst->devClipBounds()),
864 nullptr, true, SkTPin(scaleFactor, 0.f, 1.f));
865 if (requiredInput.isEmpty()) {
866 return;
867 }
868
869 // The above mapping transforms from local to dst's device space, where the layer space
870 // represents the intermediate buffer. Now we need to determine the transform from src to
871 // intermediate to prepare the input to the filter.
872 if (!localToSrc.invert(&srcToIntermediate)) {
873 return;
874 }
875 srcToIntermediate.postConcat(mapping.layerMatrix());
876 if (draw_layer_as_sprite(srcToIntermediate, srcDims)) {
877 // src differs from intermediate by just an integer translation, so it can be applied
878 // automatically when taking a subset of src if we update the mapping.
879 skif::LayerSpace<SkIPoint> srcOrigin({(int) srcToIntermediate.getTranslateX(),
880 (int) srcToIntermediate.getTranslateY()});
881 mapping.applyOrigin(srcOrigin);
882 requiredInput.offset(-srcOrigin);
883 } else {
884 // The contents of 'src' will be drawn to an intermediate buffer using srcToIntermediate
885 // and that buffer will be the input to the image filter.
886 needsIntermediateImage = true;
887 }
888 }
889
890 sk_sp<SkSpecialImage> filterInput;
891 if (!needsIntermediateImage) {
892 // The src device can be snapped directly
893 skif::LayerSpace<SkIRect> srcSubset(SkIRect::MakeSize(srcDims));
894 if (srcSubset.intersect(requiredInput)) {
895 filterInput = src->snapSpecial(SkIRect(srcSubset));
896
897 // TODO: For now image filter input images need to have a (0,0) origin. The required
898 // input's top left has been baked into srcSubset so we use that as the image origin.
899 mapping.applyOrigin(srcSubset.topLeft());
900 }
901 } else {
902 // We need to produce a temporary image that is equivalent to 'src' but transformed to
903 // a coordinate space compatible with the image filter
904
905 // TODO: If the srcToIntermediate is scale+translate, can we use the framebuffer blit
906 // extensions to handle doing the copy and scale at the same time?
907
908 SkASSERT(compat == DeviceCompatibleWithFilter::kUnknown);
909 SkRect srcRect;
910 if (!SkMatrixPriv::InverseMapRect(srcToIntermediate, &srcRect,
911 SkRect::Make(SkIRect(requiredInput)))) {
912 return;
913 }
914
915 SkIRect srcSubset = srcRect.roundOut();
916 sk_sp<SkSpecialImage> srcImage;
917 if (srcSubset.intersect(SkIRect::MakeSize(srcDims)) &&
918 (srcImage = src->snapSpecial(srcSubset))) {
919 // Make a new surface and draw 'srcImage' into it with the srcToIntermediate transform
920 // to produce the final input image for the filter
921 SkBaseDevice::CreateInfo info(make_layer_info(src->imageInfo(), requiredInput.width(),
922 requiredInput.height(), false),
923 SkPixelGeometry::kUnknown_SkPixelGeometry,
924 SkBaseDevice::TileUsage::kNever_TileUsage,
925 false, fAllocator.get());
926 sk_sp<SkBaseDevice> intermediateDevice(src->onCreateDevice(info, &paint));
927 if (!intermediateDevice) {
928 return;
929 }
930 intermediateDevice->setOrigin(SkM44(srcToIntermediate),
931 requiredInput.left(), requiredInput.top());
932
933 SkMatrix offsetLocalToDevice = intermediateDevice->localToDevice();
934 offsetLocalToDevice.preTranslate(srcSubset.left(), srcSubset.top());
935 // We draw with non-AA bilinear since we cover the destination but definitely don't have
936 // a pixel-aligned transform.
937 intermediateDevice->drawSpecial(srcImage.get(), offsetLocalToDevice,
938 SkSamplingOptions{SkFilterMode::kLinear}, {});
939 filterInput = intermediateDevice->snapSpecial();
940
941 // TODO: Like the non-intermediate case, we need to apply the image origin.
942 mapping.applyOrigin(requiredInput.topLeft());
943 }
944 }
945
946 if (filterInput) {
947 const bool use_nn = draw_layer_as_sprite(mapping.deviceMatrix(),
948 filterInput->subset().size());
949 SkSamplingOptions sampling{use_nn ? SkFilterMode::kNearest : SkFilterMode::kLinear};
950 if (filter) {
951 dst->drawFilteredImage(mapping, filterInput.get(), filter, sampling, paint);
952 } else {
953 dst->drawSpecial(filterInput.get(), mapping.deviceMatrix(), sampling, paint);
954 }
955 }
956 }
957
958 // This is similar to image_to_color_filter used by AutoLayerForImageFilter, but with key changes:
959 // - image_to_color_filter requires the entire image filter DAG to be represented as a color filter
960 // that does not affect transparent black (SkImageFilter::asAColorFilter)
961 // - when that is met, the image filter's CF is composed around any CF that was on the draw's paint
962 // since for a draw, the color filtering happens before any image filtering
963 // - optimize_layer_filter only applies to the last node and does not care about transparent black
964 // since a layer is being made regardless (SkImageFilter::isColorFilterNode)
965 // - any extracted CF is composed inside the restore paint's CF because image filters are evaluated
966 // before the color filter of a restore paint for layers.
967 //
968 // Assumes that 'filter', and thus its inputs, will remain owned by the caller. Modifies 'paint'
969 // to have the updated color filter and returns the image filter to evaluate on restore.
970 //
971 // FIXME: skbug.com/12083 - we modify 'coversDevice' here because for now, only the color filter
972 // produced from an image filter node is checked for affecting transparent black, even though it's
973 // better in the long run to have any CF that affects transparent black expand to the clip.
optimize_layer_filter(const SkImageFilter * filter,SkPaint * paint,bool * coversDevice=nullptr)974 static const SkImageFilter* optimize_layer_filter(const SkImageFilter* filter, SkPaint* paint,
975 bool* coversDevice=nullptr) {
976 SkASSERT(paint);
977 SkColorFilter* cf;
978 if (filter && filter->isColorFilterNode(&cf)) {
979 sk_sp<SkColorFilter> inner(cf);
980 if (paint->getAlphaf() < 1.f) {
981 // The paint's alpha is applied after the image filter but before the paint's color
982 // filter. If there is transparency, we have to apply it between the two filters.
983 // FIXME: The Blend CF should allow composing directly at construction.
984 inner = SkColorFilters::Compose(
985 SkColorFilters::Blend(/* src */ paint->getColor(), SkBlendMode::kDstIn),
986 /* dst */ std::move(inner));
987 paint->setAlphaf(1.f);
988 }
989
990 // Check if the once-wrapped color filter affects transparent black *before* we combine
991 // it with any original color filter on the paint.
992 if (coversDevice) {
993 *coversDevice = as_CFB(inner)->affectsTransparentBlack();
994 }
995
996 paint->setColorFilter(SkColorFilters::Compose(paint->refColorFilter(), std::move(inner)));
997 SkASSERT(filter->countInputs() == 1);
998 return filter->getInput(0);
999 } else {
1000 if (coversDevice) {
1001 *coversDevice = false;
1002 }
1003 return filter;
1004 }
1005 }
1006
1007 // If there is a backdrop filter, or if the restore paint has a color filter that affects
1008 // transparent black, then the new layer must be sized such that it covers the entire device
1009 // clip bounds of the prior device (otherwise edges of the temporary layer would be visible).
1010 // See skbug.com/8783
must_cover_prior_device(const SkImageFilter * backdrop,const SkPaint & restorePaint)1011 static bool must_cover_prior_device(const SkImageFilter* backdrop,
1012 const SkPaint& restorePaint) {
1013 // FIXME(michaelludwig) - see skbug.com/12083, once clients do not depend on user bounds for
1014 // clipping a layer visually, we can respect the fact that the color filter affects transparent
1015 // black and should cover the device.
1016 return SkToBool(backdrop); // ||
1017 // (restorePaint.getColorFilter() &&
1018 // as_CFB(restorePaint.getColorFilter())->affectsTransparentBlack());
1019 }
1020
internalSaveLayer(const SaveLayerRec & rec,SaveLayerStrategy strategy)1021 void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1022 TRACE_EVENT0("skia", TRACE_FUNC);
1023 // Do this before we create the layer. We don't call the public save() since that would invoke a
1024 // possibly overridden virtual.
1025 this->internalSave();
1026
1027 if (this->isClipEmpty()) {
1028 // Early out if the layer wouldn't draw anything
1029 return;
1030 }
1031
1032 // Build up the paint for restoring the layer, taking only the pieces of rec.fPaint that are
1033 // relevant. Filtering is automatically chosen in internalDrawDeviceWithFilter based on the
1034 // device's coordinate space.
1035 SkPaint restorePaint(rec.fPaint ? *rec.fPaint : SkPaint());
1036 restorePaint.setMaskFilter(nullptr); // mask filters are ignored for saved layers
1037 restorePaint.setImageFilter(nullptr); // the image filter is held separately
1038 // Smooth non-axis-aligned layer edges; this automatically downgrades to non-AA for aligned
1039 // layer restores. This is done to match legacy behavior where the post-applied MatrixTransform
1040 // bilerp also smoothed cropped edges. See skbug.com/11252
1041 restorePaint.setAntiAlias(true);
1042
1043 bool optimizedCFAffectsTransparent;
1044 const SkImageFilter* filter = optimize_layer_filter(
1045 rec.fPaint ? rec.fPaint->getImageFilter() : nullptr, &restorePaint,
1046 &optimizedCFAffectsTransparent);
1047
1048 // Size the new layer relative to the prior device, which may already be aligned for filters.
1049 SkBaseDevice* priorDevice = this->topDevice();
1050 skif::Mapping newLayerMapping;
1051 skif::LayerSpace<SkIRect> layerBounds;
1052 std::tie(newLayerMapping, layerBounds) = get_layer_mapping_and_bounds(
1053 filter, priorDevice->localToDevice(),
1054 skif::DeviceSpace<SkIRect>(priorDevice->devClipBounds()),
1055 skif::ParameterSpace<SkRect>::Optional(rec.fBounds),
1056 must_cover_prior_device(rec.fBackdrop, restorePaint) || optimizedCFAffectsTransparent);
1057
1058 auto abortLayer = [this]() {
1059 // The filtered content would not draw anything, or the new device space has an invalid
1060 // coordinate system, in which case we mark the current top device as empty so that nothing
1061 // draws until the canvas is restored past this saveLayer.
1062 AutoUpdateQRBounds aqr(this);
1063 this->topDevice()->clipRect(SkRect::MakeEmpty(), SkClipOp::kIntersect, /* aa */ false);
1064 };
1065
1066 if (layerBounds.isEmpty()) {
1067 abortLayer();
1068 return;
1069 }
1070
1071 sk_sp<SkBaseDevice> newDevice;
1072 if (strategy == kFullLayer_SaveLayerStrategy) {
1073 SkASSERT(!layerBounds.isEmpty());
1074 SkImageInfo info = make_layer_info(priorDevice->imageInfo(),
1075 layerBounds.width(), layerBounds.height(),
1076 SkToBool(rec.fSaveLayerFlags & kF16ColorType));
1077 if (rec.fSaveLayerFlags & kF16ColorType) {
1078 info = info.makeColorType(kRGBA_F16_SkColorType);
1079 }
1080 SkASSERT(info.alphaType() != kOpaque_SkAlphaType);
1081
1082 SkPixelGeometry geo = rec.fSaveLayerFlags & kPreserveLCDText_SaveLayerFlag
1083 ? fProps.pixelGeometry()
1084 : kUnknown_SkPixelGeometry;
1085 const bool trackCoverage = SkToBool(
1086 rec.fSaveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
1087 const auto createInfo = SkBaseDevice::CreateInfo(info, geo, SkBaseDevice::kNever_TileUsage,
1088 trackCoverage, fAllocator.get());
1089 // Use the original paint as a hint so that it includes the image filter
1090 newDevice.reset(priorDevice->onCreateDevice(createInfo, rec.fPaint));
1091 }
1092
1093 bool initBackdrop = (rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop;
1094 if (!newDevice) {
1095 // Either we weren't meant to allocate a full layer, or the full layer creation failed.
1096 // Using an explicit NoPixelsDevice lets us reflect what the layer state would have been
1097 // on success (or kFull_LayerStrategy) while squashing draw calls that target something that
1098 // doesn't exist.
1099 newDevice = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeWH(layerBounds.width(),
1100 layerBounds.height()),
1101 fProps, this->imageInfo().refColorSpace());
1102 initBackdrop = false;
1103 }
1104
1105 // Configure device to match determined mapping for any image filters.
1106 // The setDeviceCoordinateSystem applies the prior device's global transform since
1107 // 'newLayerMapping' only defines the transforms between the two devices and it must be updated
1108 // to the global coordinate system.
1109 newDevice->setMarkerStack(fMarkerStack.get());
1110 if (!newDevice->setDeviceCoordinateSystem(priorDevice->deviceToGlobal() *
1111 SkM44(newLayerMapping.deviceMatrix()),
1112 SkM44(newLayerMapping.layerMatrix()),
1113 layerBounds.left(), layerBounds.top())) {
1114 // If we made it this far and the coordinate system is invalid, we most likely had a valid
1115 // mapping until being combined with the previous device-to-global matrix, at which point
1116 // it overflowed or floating point rounding caused it to no longer be invertible. There's
1117 // not much we can do but clean up the layer and mark the clip as empty. This tends to come
1118 // up in fuzzer-generated inputs, so this policy is not unreasonable and helps avoids UB.
1119 newDevice = nullptr;
1120 abortLayer();
1121 return;
1122 }
1123
1124 if (initBackdrop) {
1125 SkPaint backdropPaint;
1126 const SkImageFilter* backdropFilter = optimize_layer_filter(rec.fBackdrop, &backdropPaint);
1127 // The new device was constructed to be compatible with 'filter', not necessarily
1128 // 'rec.fBackdrop', so allow DrawDeviceWithFilter to transform the prior device contents
1129 // if necessary to evaluate the backdrop filter. If no filters are involved, then the
1130 // devices differ by integer translations and are always compatible.
1131 bool scaleBackdrop = rec.fExperimentalBackdropScale != 1.0f;
1132 auto compat = (filter || backdropFilter || scaleBackdrop)
1133 ? DeviceCompatibleWithFilter::kUnknown : DeviceCompatibleWithFilter::kYes;
1134 this->internalDrawDeviceWithFilter(priorDevice, // src
1135 newDevice.get(), // dst
1136 backdropFilter,
1137 backdropPaint,
1138 compat,
1139 rec.fExperimentalBackdropScale);
1140 }
1141
1142 fMCRec->newLayer(std::move(newDevice), sk_ref_sp(filter), restorePaint);
1143 fQuickRejectBounds = this->computeDeviceClipBounds();
1144 }
1145
saveLayerAlpha(const SkRect * bounds,U8CPU alpha)1146 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1147 if (0xFF == alpha) {
1148 return this->saveLayer(bounds, nullptr);
1149 } else {
1150 SkPaint tmpPaint;
1151 tmpPaint.setAlpha(alpha);
1152 return this->saveLayer(bounds, &tmpPaint);
1153 }
1154 }
1155
internalSaveBehind(const SkRect * localBounds)1156 void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1157 SkBaseDevice* device = this->topDevice();
1158
1159 // Map the local bounds into the top device's coordinate space (this is not
1160 // necessarily the full global CTM transform).
1161 SkIRect devBounds;
1162 if (localBounds) {
1163 SkRect tmp;
1164 device->localToDevice().mapRect(&tmp, *localBounds);
1165 if (!devBounds.intersect(tmp.round(), device->devClipBounds())) {
1166 devBounds.setEmpty();
1167 }
1168 } else {
1169 devBounds = device->devClipBounds();
1170 }
1171 if (devBounds.isEmpty()) {
1172 return;
1173 }
1174
1175 // This is getting the special image from the current device, which is then drawn into (both by
1176 // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its
1177 // own device, we need to explicitly copy the back image contents so that its original content
1178 // is available when we splat it back later during restore.
1179 auto backImage = device->snapSpecial(devBounds, /* copy */ true);
1180 if (!backImage) {
1181 return;
1182 }
1183
1184 // we really need the save, so we can wack the fMCRec
1185 this->checkForDeferredSave();
1186
1187 fMCRec->fBackImage =
1188 std::make_unique<BackImage>(BackImage{std::move(backImage), devBounds.topLeft()});
1189
1190 SkPaint paint;
1191 paint.setBlendMode(SkBlendMode::kClear);
1192 this->drawClippedToSaveBehind(paint);
1193 }
1194
internalRestore()1195 SK_ALWAYS_INLINE void SkCanvas::internalRestore() {
1196 SkASSERT(!fMCStack.empty());
1197
1198 // now detach these from fMCRec so we can pop(). Gets freed after its drawn
1199 std::unique_ptr<Layer> layer = std::move(fMCRec->fLayer);
1200 std::unique_ptr<BackImage> backImage = std::move(fMCRec->fBackImage);
1201
1202 fMarkerStack->restore(fMCRec);
1203
1204 // now do the normal restore()
1205 fMCRec->~MCRec(); // balanced in save()
1206 fMCStack.pop_back();
1207 fMCRec = (MCRec*) fMCStack.back();
1208
1209 if (!fMCRec) {
1210 // This was the last record, restored during the destruction of the SkCanvas
1211 return;
1212 }
1213
1214 this->topDevice()->restore(fMCRec->fMatrix);
1215
1216 if (backImage) {
1217 SkPaint paint;
1218 paint.setBlendMode(SkBlendMode::kDstOver);
1219 this->topDevice()->drawSpecial(backImage->fImage.get(),
1220 SkMatrix::Translate(backImage->fLoc),
1221 SkSamplingOptions(),
1222 paint);
1223 }
1224
1225 // Draw the layer's device contents into the now-current older device. We can't call public
1226 // draw functions since we don't want to record them.
1227 if (layer && !layer->fDevice->isNoPixelsDevice() && !layer->fDiscard) {
1228 layer->fDevice->setImmutable();
1229
1230 // Don't go through AutoLayerForImageFilter since device draws are so closely tied to
1231 // internalSaveLayer and internalRestore.
1232 if (this->predrawNotify()) {
1233 SkBaseDevice* dstDev = this->topDevice();
1234 if (layer->fImageFilter) {
1235 this->internalDrawDeviceWithFilter(layer->fDevice.get(), // src
1236 dstDev, // dst
1237 layer->fImageFilter.get(),
1238 layer->fPaint,
1239 DeviceCompatibleWithFilter::kYes);
1240 } else {
1241 // NOTE: We don't just call internalDrawDeviceWithFilter with a null filter
1242 // because we want to take advantage of overridden drawDevice functions for
1243 // document-based devices.
1244 SkSamplingOptions sampling;
1245 dstDev->drawDevice(layer->fDevice.get(), sampling, layer->fPaint);
1246 }
1247 }
1248 }
1249
1250 // Reset the clip restriction if the restore went past the save point that had added it.
1251 if (this->getSaveCount() < fClipRestrictionSaveCount) {
1252 fClipRestrictionRect.setEmpty();
1253 fClipRestrictionSaveCount = -1;
1254 }
1255 // Update the quick-reject bounds in case the restore changed the top device or the
1256 // removed save record had included modifications to the clip stack.
1257 fQuickRejectBounds = this->computeDeviceClipBounds();
1258 this->validateClip();
1259 }
1260
makeSurface(const SkImageInfo & info,const SkSurfaceProps * props)1261 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1262 if (nullptr == props) {
1263 props = &fProps;
1264 }
1265 return this->onNewSurface(info, *props);
1266 }
1267
onNewSurface(const SkImageInfo & info,const SkSurfaceProps & props)1268 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1269 return this->baseDevice()->makeSurface(info, props);
1270 }
1271
imageInfo() const1272 SkImageInfo SkCanvas::imageInfo() const {
1273 return this->onImageInfo();
1274 }
1275
onImageInfo() const1276 SkImageInfo SkCanvas::onImageInfo() const {
1277 return this->baseDevice()->imageInfo();
1278 }
1279
getProps(SkSurfaceProps * props) const1280 bool SkCanvas::getProps(SkSurfaceProps* props) const {
1281 return this->onGetProps(props);
1282 }
1283
onGetProps(SkSurfaceProps * props) const1284 bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
1285 if (props) {
1286 *props = fProps;
1287 }
1288 return true;
1289 }
1290
peekPixels(SkPixmap * pmap)1291 bool SkCanvas::peekPixels(SkPixmap* pmap) {
1292 return this->onPeekPixels(pmap);
1293 }
1294
onPeekPixels(SkPixmap * pmap)1295 bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
1296 return this->baseDevice()->peekPixels(pmap);
1297 }
1298
accessTopLayerPixels(SkImageInfo * info,size_t * rowBytes,SkIPoint * origin)1299 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1300 SkPixmap pmap;
1301 if (!this->onAccessTopLayerPixels(&pmap)) {
1302 return nullptr;
1303 }
1304 if (info) {
1305 *info = pmap.info();
1306 }
1307 if (rowBytes) {
1308 *rowBytes = pmap.rowBytes();
1309 }
1310 if (origin) {
1311 // If the caller requested the origin, they presumably are expecting the returned pixels to
1312 // be axis-aligned with the root canvas. If the top level device isn't axis aligned, that's
1313 // not the case. Until we update accessTopLayerPixels() to accept a coord space matrix
1314 // instead of an origin, just don't expose the pixels in that case. Note that this means
1315 // that layers with complex coordinate spaces can still report their pixels if the caller
1316 // does not ask for the origin (e.g. just to dump its output to a file, etc).
1317 if (this->topDevice()->isPixelAlignedToGlobal()) {
1318 *origin = this->topDevice()->getOrigin();
1319 } else {
1320 return nullptr;
1321 }
1322 }
1323 return pmap.writable_addr();
1324 }
1325
onAccessTopLayerPixels(SkPixmap * pmap)1326 bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
1327 return this->topDevice()->accessPixels(pmap);
1328 }
1329
1330 /////////////////////////////////////////////////////////////////////////////
1331
translate(SkScalar dx,SkScalar dy)1332 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1333 if (dx || dy) {
1334 this->checkForDeferredSave();
1335 fMCRec->fMatrix.preTranslate(dx, dy);
1336
1337 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1338
1339 this->didTranslate(dx,dy);
1340 }
1341 }
1342
scale(SkScalar sx,SkScalar sy)1343 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1344 if (sx != 1 || sy != 1) {
1345 this->checkForDeferredSave();
1346 fMCRec->fMatrix.preScale(sx, sy);
1347
1348 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1349
1350 this->didScale(sx, sy);
1351 }
1352 }
1353
rotate(SkScalar degrees)1354 void SkCanvas::rotate(SkScalar degrees) {
1355 SkMatrix m;
1356 m.setRotate(degrees);
1357 this->concat(m);
1358 }
1359
rotate(SkScalar degrees,SkScalar px,SkScalar py)1360 void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1361 SkMatrix m;
1362 m.setRotate(degrees, px, py);
1363 this->concat(m);
1364 }
1365
skew(SkScalar sx,SkScalar sy)1366 void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1367 SkMatrix m;
1368 m.setSkew(sx, sy);
1369 this->concat(m);
1370 }
1371
concat(const SkMatrix & matrix)1372 void SkCanvas::concat(const SkMatrix& matrix) {
1373 if (matrix.isIdentity()) {
1374 return;
1375 }
1376 this->concat(SkM44(matrix));
1377 }
1378
internalConcat44(const SkM44 & m)1379 void SkCanvas::internalConcat44(const SkM44& m) {
1380 this->checkForDeferredSave();
1381
1382 fMCRec->fMatrix.preConcat(m);
1383
1384 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1385 }
1386
concat(const SkM44 & m)1387 void SkCanvas::concat(const SkM44& m) {
1388 this->internalConcat44(m);
1389 // notify subclasses
1390 this->didConcat44(m);
1391 }
1392
internalSetMatrix(const SkM44 & m)1393 void SkCanvas::internalSetMatrix(const SkM44& m) {
1394 fMCRec->fMatrix = m;
1395
1396 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1397 }
1398
setMatrix(const SkMatrix & matrix)1399 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1400 this->setMatrix(SkM44(matrix));
1401 }
1402
setMatrix(const SkM44 & m)1403 void SkCanvas::setMatrix(const SkM44& m) {
1404 this->checkForDeferredSave();
1405 this->internalSetMatrix(m);
1406 this->didSetM44(m);
1407 }
1408
resetMatrix()1409 void SkCanvas::resetMatrix() {
1410 this->setMatrix(SkM44());
1411 }
1412
markCTM(const char * name)1413 void SkCanvas::markCTM(const char* name) {
1414 if (SkCanvasPriv::ValidateMarker(name)) {
1415 fMarkerStack->setMarker(SkOpts::hash_fn(name, strlen(name), 0),
1416 this->getLocalToDevice(), fMCRec);
1417 this->onMarkCTM(name);
1418 }
1419 }
1420
findMarkedCTM(const char * name,SkM44 * mx) const1421 bool SkCanvas::findMarkedCTM(const char* name, SkM44* mx) const {
1422 return SkCanvasPriv::ValidateMarker(name) &&
1423 fMarkerStack->findMarker(SkOpts::hash_fn(name, strlen(name), 0), mx);
1424 }
1425
1426 //////////////////////////////////////////////////////////////////////////////
1427
clipRect(const SkRect & rect,SkClipOp op,bool doAA)1428 void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
1429 if (!rect.isFinite()) {
1430 return;
1431 }
1432 this->checkForDeferredSave();
1433 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1434 this->onClipRect(rect.makeSorted(), op, edgeStyle);
1435 }
1436
onClipRect(const SkRect & rect,SkClipOp op,ClipEdgeStyle edgeStyle)1437 void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1438 SkASSERT(rect.isSorted());
1439 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1440
1441 AutoUpdateQRBounds aqr(this);
1442 this->topDevice()->clipRect(rect, op, isAA);
1443 }
1444
androidFramework_setDeviceClipRestriction(const SkIRect & rect)1445 void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1446 // The device clip restriction is a surface-space rectangular intersection that cannot be
1447 // drawn outside of. The rectangle is remembered so that subsequent resetClip calls still
1448 // respect the restriction. Other than clip resetting, all clip operations restrict the set
1449 // of renderable pixels, so once set, the restriction will be respected until the canvas
1450 // save stack is restored past the point this function was invoked. Unfortunately, the current
1451 // implementation relies on the clip stack of the underyling SkDevices, which leads to some
1452 // awkward behavioral interactions (see skbug.com/12252).
1453 //
1454 // Namely, a canvas restore() could undo the clip restriction's rect, and if
1455 // setDeviceClipRestriction were called at a nested save level, there's no way to undo just the
1456 // prior restriction and re-apply the new one. It also only makes sense to apply to the base
1457 // device; any other device for a saved layer will be clipped back to the base device during its
1458 // matched restore. As such, we:
1459 // - Remember the save count that added the clip restriction and reset the rect to empty when
1460 // we've restored past that point to keep our state in sync with the device's clip stack.
1461 // - We assert that we're on the base device when this is invoked.
1462 // - We assert that setDeviceClipRestriction() is only called when there was no prior
1463 // restriction (cannot re-restrict, and prior state must have been reset by restoring the
1464 // canvas state).
1465 // - Historically, the empty rect would reset the clip restriction but it only could do so
1466 // partially since the device's clips wasn't adjusted. Resetting is now handled
1467 // automatically via SkCanvas::restore(), so empty input rects are skipped.
1468 SkASSERT(this->topDevice() == this->baseDevice()); // shouldn't be in a nested layer
1469 // and shouldn't already have a restriction
1470 SkASSERT(fClipRestrictionSaveCount < 0 && fClipRestrictionRect.isEmpty());
1471
1472 if (fClipRestrictionSaveCount < 0 && !rect.isEmpty()) {
1473 fClipRestrictionRect = rect;
1474 fClipRestrictionSaveCount = this->getSaveCount();
1475
1476 // A non-empty clip restriction immediately applies an intersection op (ignoring the ctm).
1477 // so we have to resolve the save.
1478 this->checkForDeferredSave();
1479 AutoUpdateQRBounds aqr(this);
1480 // Use clipRegion() since that operates in canvas-space, whereas clipRect() would apply the
1481 // device's current transform first.
1482 this->topDevice()->clipRegion(SkRegion(rect), SkClipOp::kIntersect);
1483 }
1484 }
1485
internal_private_resetClip()1486 void SkCanvas::internal_private_resetClip() {
1487 this->checkForDeferredSave();
1488 this->onResetClip();
1489 }
1490
onResetClip()1491 void SkCanvas::onResetClip() {
1492 SkIRect deviceRestriction = this->topDevice()->imageInfo().bounds();
1493 if (fClipRestrictionSaveCount >= 0 && this->topDevice() == this->baseDevice()) {
1494 // Respect the device clip restriction when resetting the clip if we're on the base device.
1495 // If we're not on the base device, then the "reset" applies to the top device's clip stack,
1496 // and the clip restriction will be respected automatically during a restore of the layer.
1497 if (!deviceRestriction.intersect(fClipRestrictionRect)) {
1498 deviceRestriction = SkIRect::MakeEmpty();
1499 }
1500 }
1501
1502 AutoUpdateQRBounds aqr(this);
1503 this->topDevice()->replaceClip(deviceRestriction);
1504 }
1505
clipRRect(const SkRRect & rrect,SkClipOp op,bool doAA)1506 void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
1507 this->checkForDeferredSave();
1508 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1509 if (rrect.isRect()) {
1510 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1511 } else {
1512 this->onClipRRect(rrect, op, edgeStyle);
1513 }
1514 }
1515
onClipRRect(const SkRRect & rrect,SkClipOp op,ClipEdgeStyle edgeStyle)1516 void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1517 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1518
1519 AutoUpdateQRBounds aqr(this);
1520 this->topDevice()->clipRRect(rrect, op, isAA);
1521 }
1522
clipPath(const SkPath & path,SkClipOp op,bool doAA)1523 void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
1524 this->checkForDeferredSave();
1525 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1526
1527 if (!path.isInverseFillType() && fMCRec->fMatrix.asM33().rectStaysRect()) {
1528 SkRect r;
1529 if (path.isRect(&r)) {
1530 this->onClipRect(r, op, edgeStyle);
1531 return;
1532 }
1533 SkRRect rrect;
1534 if (path.isOval(&r)) {
1535 rrect.setOval(r);
1536 this->onClipRRect(rrect, op, edgeStyle);
1537 return;
1538 }
1539 if (path.isRRect(&rrect)) {
1540 this->onClipRRect(rrect, op, edgeStyle);
1541 return;
1542 }
1543 }
1544
1545 this->onClipPath(path, op, edgeStyle);
1546 }
1547
onClipPath(const SkPath & path,SkClipOp op,ClipEdgeStyle edgeStyle)1548 void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
1549 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1550
1551 AutoUpdateQRBounds aqr(this);
1552 this->topDevice()->clipPath(path, op, isAA);
1553 }
1554
clipShader(sk_sp<SkShader> sh,SkClipOp op)1555 void SkCanvas::clipShader(sk_sp<SkShader> sh, SkClipOp op) {
1556 if (sh) {
1557 if (sh->isOpaque()) {
1558 if (op == SkClipOp::kIntersect) {
1559 // we don't occlude anything, so skip this call
1560 } else {
1561 SkASSERT(op == SkClipOp::kDifference);
1562 // we occlude everything, so set the clip to empty
1563 this->clipRect({0,0,0,0});
1564 }
1565 } else {
1566 this->checkForDeferredSave();
1567 this->onClipShader(std::move(sh), op);
1568 }
1569 }
1570 }
1571
onClipShader(sk_sp<SkShader> sh,SkClipOp op)1572 void SkCanvas::onClipShader(sk_sp<SkShader> sh, SkClipOp op) {
1573 AutoUpdateQRBounds aqr(this);
1574 this->topDevice()->clipShader(sh, op);
1575 }
1576
clipRegion(const SkRegion & rgn,SkClipOp op)1577 void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
1578 this->checkForDeferredSave();
1579 this->onClipRegion(rgn, op);
1580 }
1581
onClipRegion(const SkRegion & rgn,SkClipOp op)1582 void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
1583 AutoUpdateQRBounds aqr(this);
1584 this->topDevice()->clipRegion(rgn, op);
1585 }
1586
validateClip() const1587 void SkCanvas::validateClip() const {
1588 #ifdef SK_DEBUG
1589 SkRect tmp = this->computeDeviceClipBounds();
1590 if (this->isClipEmpty()) {
1591 SkASSERT(fQuickRejectBounds.isEmpty());
1592 } else {
1593 SkASSERT(tmp == fQuickRejectBounds);
1594 }
1595 #endif
1596 }
1597
androidFramework_isClipAA() const1598 bool SkCanvas::androidFramework_isClipAA() const {
1599 return this->topDevice()->onClipIsAA();
1600 }
1601
temporary_internal_getRgnClip(SkRegion * rgn)1602 void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1603 rgn->setEmpty();
1604 SkBaseDevice* device = this->topDevice();
1605 if (device && device->isPixelAlignedToGlobal()) {
1606 device->onAsRgnClip(rgn);
1607 SkIPoint origin = device->getOrigin();
1608 if (origin.x() | origin.y()) {
1609 rgn->translate(origin.x(), origin.y());
1610 }
1611 }
1612 }
1613
1614 ///////////////////////////////////////////////////////////////////////////////
1615
isClipEmpty() const1616 bool SkCanvas::isClipEmpty() const {
1617 return this->topDevice()->onGetClipType() == SkBaseDevice::ClipType::kEmpty;
1618 }
1619
isClipRect() const1620 bool SkCanvas::isClipRect() const {
1621 return this->topDevice()->onGetClipType() == SkBaseDevice::ClipType::kRect;
1622 }
1623
quickReject(const SkRect & src) const1624 bool SkCanvas::quickReject(const SkRect& src) const {
1625 #ifdef SK_DEBUG
1626 // Verify that fQuickRejectBounds are set properly.
1627 this->validateClip();
1628 #endif
1629
1630 SkRect devRect = SkMatrixPriv::MapRect(fMCRec->fMatrix, src);
1631 return !devRect.isFinite() || !devRect.intersects(fQuickRejectBounds);
1632 }
1633
quickReject(const SkPath & path) const1634 bool SkCanvas::quickReject(const SkPath& path) const {
1635 return path.isEmpty() || this->quickReject(path.getBounds());
1636 }
1637
internalQuickReject(const SkRect & bounds,const SkPaint & paint,const SkMatrix * matrix)1638 bool SkCanvas::internalQuickReject(const SkRect& bounds, const SkPaint& paint,
1639 const SkMatrix* matrix) {
1640 if (!bounds.isFinite() || paint.nothingToDraw()) {
1641 return true;
1642 }
1643
1644 if (paint.canComputeFastBounds()) {
1645 SkRect tmp = matrix ? matrix->mapRect(bounds) : bounds;
1646 return this->quickReject(paint.computeFastBounds(tmp, &tmp));
1647 }
1648
1649 return false;
1650 }
1651
1652
getLocalClipBounds() const1653 SkRect SkCanvas::getLocalClipBounds() const {
1654 SkIRect ibounds = this->getDeviceClipBounds();
1655 if (ibounds.isEmpty()) {
1656 return SkRect::MakeEmpty();
1657 }
1658
1659 SkMatrix inverse;
1660 // if we can't invert the CTM, we can't return local clip bounds
1661 if (!fMCRec->fMatrix.asM33().invert(&inverse)) {
1662 return SkRect::MakeEmpty();
1663 }
1664
1665 SkRect bounds;
1666 // adjust it outwards in case we are antialiasing
1667 const int margin = 1;
1668
1669 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
1670 inverse.mapRect(&bounds, r);
1671 return bounds;
1672 }
1673
getRoundInDeviceClipBounds() const1674 SkIRect SkCanvas::getRoundInDeviceClipBounds() const {
1675 return this->computeDeviceClipBounds(/*outsetForAA=*/false).roundIn();
1676 }
1677
getDeviceClipBounds() const1678 SkIRect SkCanvas::getDeviceClipBounds() const {
1679 return this->computeDeviceClipBounds(/*outsetForAA=*/false).roundOut();
1680 }
1681
computeDeviceClipBounds(bool outsetForAA) const1682 SkRect SkCanvas::computeDeviceClipBounds(bool outsetForAA) const {
1683 const SkBaseDevice* dev = this->topDevice();
1684 if (dev->onGetClipType() == SkBaseDevice::ClipType::kEmpty) {
1685 return SkRect::MakeEmpty();
1686 } else {
1687 SkRect devClipBounds =
1688 SkMatrixPriv::MapRect(dev->deviceToGlobal(), SkRect::Make(dev->devClipBounds()));
1689 if (outsetForAA) {
1690 // Expand bounds out by 1 in case we are anti-aliasing. We store the
1691 // bounds as floats to enable a faster quick reject implementation.
1692 devClipBounds.outset(1.f, 1.f);
1693 }
1694 return devClipBounds;
1695 }
1696 }
1697
1698 ///////////////////////////////////////////////////////////////////////
1699
getTotalMatrix() const1700 SkMatrix SkCanvas::getTotalMatrix() const {
1701 return fMCRec->fMatrix.asM33();
1702 }
1703
getLocalToDevice() const1704 SkM44 SkCanvas::getLocalToDevice() const {
1705 return fMCRec->fMatrix;
1706 }
1707
1708 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && SK_SUPPORT_GPU
1709
topLayerBounds() const1710 SkIRect SkCanvas::topLayerBounds() const {
1711 return this->topDevice()->getGlobalBounds();
1712 }
1713
topLayerBackendRenderTarget() const1714 GrBackendRenderTarget SkCanvas::topLayerBackendRenderTarget() const {
1715 auto proxy = SkCanvasPriv::TopDeviceTargetProxy(const_cast<SkCanvas*>(this));
1716 if (!proxy) {
1717 return {};
1718 }
1719 const GrRenderTarget* renderTarget = proxy->peekRenderTarget();
1720 return renderTarget ? renderTarget->getBackendRenderTarget() : GrBackendRenderTarget();
1721 }
1722 #endif
1723
recordingContext()1724 GrRecordingContext* SkCanvas::recordingContext() {
1725 #if SK_SUPPORT_GPU
1726 if (auto gpuDevice = this->topDevice()->asGpuDevice()) {
1727 return gpuDevice->recordingContext();
1728 }
1729 #endif
1730
1731 return nullptr;
1732 }
1733
drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)1734 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1735 const SkPaint& paint) {
1736 TRACE_EVENT0("skia", TRACE_FUNC);
1737 if (outer.isEmpty()) {
1738 return;
1739 }
1740 if (inner.isEmpty()) {
1741 this->drawRRect(outer, paint);
1742 return;
1743 }
1744
1745 // We don't have this method (yet), but technically this is what we should
1746 // be able to return ...
1747 // if (!outer.contains(inner))) {
1748 //
1749 // For now at least check for containment of bounds
1750 if (!outer.getBounds().contains(inner.getBounds())) {
1751 return;
1752 }
1753
1754 this->onDrawDRRect(outer, inner, paint);
1755 }
1756
drawPaint(const SkPaint & paint)1757 void SkCanvas::drawPaint(const SkPaint& paint) {
1758 TRACE_EVENT0("skia", TRACE_FUNC);
1759 this->onDrawPaint(paint);
1760 }
1761
drawRect(const SkRect & r,const SkPaint & paint)1762 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1763 TRACE_EVENT0("skia", TRACE_FUNC);
1764 // To avoid redundant logic in our culling code and various backends, we always sort rects
1765 // before passing them along.
1766 this->onDrawRect(r.makeSorted(), paint);
1767 }
1768
drawClippedToSaveBehind(const SkPaint & paint)1769 void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1770 TRACE_EVENT0("skia", TRACE_FUNC);
1771 this->onDrawBehind(paint);
1772 }
1773
drawRegion(const SkRegion & region,const SkPaint & paint)1774 void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1775 TRACE_EVENT0("skia", TRACE_FUNC);
1776 if (region.isEmpty()) {
1777 return;
1778 }
1779
1780 if (region.isRect()) {
1781 return this->drawIRect(region.getBounds(), paint);
1782 }
1783
1784 this->onDrawRegion(region, paint);
1785 }
1786
drawOval(const SkRect & r,const SkPaint & paint)1787 void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1788 TRACE_EVENT0("skia", TRACE_FUNC);
1789 // To avoid redundant logic in our culling code and various backends, we always sort rects
1790 // before passing them along.
1791 this->onDrawOval(r.makeSorted(), paint);
1792 }
1793
drawRRect(const SkRRect & rrect,const SkPaint & paint)1794 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1795 TRACE_EVENT0("skia", TRACE_FUNC);
1796 this->onDrawRRect(rrect, paint);
1797 }
1798
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1799 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1800 TRACE_EVENT0("skia", TRACE_FUNC);
1801 this->onDrawPoints(mode, count, pts, paint);
1802 }
1803
drawVertices(const sk_sp<SkVertices> & vertices,SkBlendMode mode,const SkPaint & paint)1804 void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1805 const SkPaint& paint) {
1806 this->drawVertices(vertices.get(), mode, paint);
1807 }
1808
drawVertices(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)1809 void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1810 TRACE_EVENT0("skia", TRACE_FUNC);
1811 RETURN_ON_NULL(vertices);
1812
1813 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1814 SkASSERT(vertices->priv().mode() != SkVertices::kTriangleFan_VertexMode);
1815
1816 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1817 // Preserve legacy behavior for Android: ignore the SkShader if there are no texCoords present
1818 if (paint.getShader() && !vertices->priv().hasTexCoords()) {
1819 SkPaint noShaderPaint(paint);
1820 noShaderPaint.setShader(nullptr);
1821 this->onDrawVerticesObject(vertices, mode, noShaderPaint);
1822 return;
1823 }
1824 #endif
1825
1826 this->onDrawVerticesObject(vertices, mode, paint);
1827 }
1828
drawPath(const SkPath & path,const SkPaint & paint)1829 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1830 TRACE_EVENT0("skia", TRACE_FUNC);
1831 this->onDrawPath(path, paint);
1832 #ifdef SK_ENABLE_PATH_COMPLEXITY_DFX
1833 SkPathComplexityDfx::ShowPathComplexityDfx(this, path);
1834 #endif
1835 }
1836
1837 #ifdef SK_ENABLE_STENCIL_CULLING_OHOS
clearStencil(const SkIRect & rect,uint32_t stencilVal)1838 void SkCanvas::clearStencil(const SkIRect& rect, uint32_t stencilVal) {
1839 TRACE_EVENT0("skia", TRACE_FUNC);
1840 this->topDevice()->clearStencil(rect, stencilVal);
1841 }
1842
drawPathWithStencil(const SkPath & path,const SkPaint & paint,uint32_t stencilRef)1843 void SkCanvas::drawPathWithStencil(const SkPath& path, const SkPaint& paint, uint32_t stencilRef) {
1844 TRACE_EVENT0("skia", TRACE_FUNC);
1845 this->onDrawPathWithStencil(path, paint, stencilRef);
1846 #ifdef SK_ENABLE_PATH_COMPLEXITY_DFX
1847 SkPathComplexityDfx::ShowPathComplexityDfx(this, path);
1848 #endif
1849 }
1850 #endif
1851
1852 // Returns true if the rect can be "filled" : non-empty and finite
fillable(const SkRect & r)1853 static bool fillable(const SkRect& r) {
1854 SkScalar w = r.width();
1855 SkScalar h = r.height();
1856 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1857 }
1858
clean_paint_for_lattice(const SkPaint * paint)1859 static SkPaint clean_paint_for_lattice(const SkPaint* paint) {
1860 SkPaint cleaned;
1861 if (paint) {
1862 cleaned = *paint;
1863 cleaned.setMaskFilter(nullptr);
1864 cleaned.setAntiAlias(false);
1865 }
1866 return cleaned;
1867 }
1868
drawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)1869 void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1870 SkFilterMode filter, const SkPaint* paint) {
1871 RETURN_ON_NULL(image);
1872
1873 const int xdivs[] = {center.fLeft, center.fRight};
1874 const int ydivs[] = {center.fTop, center.fBottom};
1875
1876 Lattice lat;
1877 lat.fXDivs = xdivs;
1878 lat.fYDivs = ydivs;
1879 lat.fRectTypes = nullptr;
1880 lat.fXCount = lat.fYCount = 2;
1881 lat.fBounds = nullptr;
1882 lat.fColors = nullptr;
1883 this->drawImageLattice(image, lat, dst, filter, paint);
1884 }
1885
drawImageLattice(const SkImage * image,const Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)1886 void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1887 SkFilterMode filter, const SkPaint* paint) {
1888 TRACE_EVENT0("skia", TRACE_FUNC);
1889 RETURN_ON_NULL(image);
1890 if (dst.isEmpty()) {
1891 return;
1892 }
1893
1894 SkIRect bounds;
1895 Lattice latticePlusBounds = lattice;
1896 if (!latticePlusBounds.fBounds) {
1897 bounds = SkIRect::MakeWH(image->width(), image->height());
1898 latticePlusBounds.fBounds = &bounds;
1899 }
1900
1901 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1902 SkPaint latticePaint = clean_paint_for_lattice(paint);
1903 this->onDrawImageLattice2(image, latticePlusBounds, dst, filter, &latticePaint);
1904 } else {
1905 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst,
1906 SkSamplingOptions(filter), paint, kStrict_SrcRectConstraint);
1907 }
1908 }
1909
drawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode mode,const SkSamplingOptions & sampling,const SkRect * cull,const SkPaint * paint)1910 void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1911 const SkColor colors[], int count, SkBlendMode mode,
1912 const SkSamplingOptions& sampling, const SkRect* cull,
1913 const SkPaint* paint) {
1914 TRACE_EVENT0("skia", TRACE_FUNC);
1915 RETURN_ON_NULL(atlas);
1916 if (count <= 0) {
1917 return;
1918 }
1919 SkASSERT(atlas);
1920 SkASSERT(tex);
1921 this->onDrawAtlas2(atlas, xform, tex, colors, count, mode, sampling, cull, paint);
1922 }
1923
drawAnnotation(const SkRect & rect,const char key[],SkData * value)1924 void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1925 TRACE_EVENT0("skia", TRACE_FUNC);
1926 if (key) {
1927 this->onDrawAnnotation(rect, key, value);
1928 }
1929 }
1930
private_draw_shadow_rec(const SkPath & path,const SkDrawShadowRec & rec)1931 void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
1932 TRACE_EVENT0("skia", TRACE_FUNC);
1933 this->onDrawShadowRec(path, rec);
1934 }
1935
onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)1936 void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1937 // We don't test quickReject because the shadow outsets the path's bounds.
1938 // TODO(michaelludwig): Is it worth calling SkDrawShadowMetrics::GetLocalBounds here?
1939 if (!this->predrawNotify()) {
1940 return;
1941 }
1942 this->topDevice()->drawShadow(path, rec);
1943 }
1944
experimental_DrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)1945 void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
1946 QuadAAFlags aaFlags, const SkColor4f& color,
1947 SkBlendMode mode) {
1948 TRACE_EVENT0("skia", TRACE_FUNC);
1949 // Make sure the rect is sorted before passing it along
1950 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
1951 }
1952
experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[],int cnt,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)1953 void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
1954 const SkPoint dstClips[],
1955 const SkMatrix preViewMatrices[],
1956 const SkSamplingOptions& sampling,
1957 const SkPaint* paint,
1958 SrcRectConstraint constraint) {
1959 TRACE_EVENT0("skia", TRACE_FUNC);
1960 this->onDrawEdgeAAImageSet2(imageSet, cnt, dstClips, preViewMatrices, sampling, paint,
1961 constraint);
1962 }
1963
1964 //////////////////////////////////////////////////////////////////////////////
1965 // These are the virtual drawing methods
1966 //////////////////////////////////////////////////////////////////////////////
1967
onDiscard()1968 void SkCanvas::onDiscard() {
1969 if (fSurfaceBase) {
1970 sk_ignore_unused_variable(fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode));
1971 }
1972 }
1973
onDrawPaint(const SkPaint & paint)1974 void SkCanvas::onDrawPaint(const SkPaint& paint) {
1975 this->internalDrawPaint(paint);
1976 }
1977
internalDrawPaint(const SkPaint & paint)1978 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1979 // drawPaint does not call internalQuickReject() because computing its geometry is not free
1980 // (see getLocalClipBounds(), and the two conditions below are sufficient.
1981 if (paint.nothingToDraw() || this->isClipEmpty()) {
1982 return;
1983 }
1984
1985 auto layer = this->aboutToDraw(this, paint, nullptr, CheckForOverwrite::kYes);
1986 if (layer) {
1987 this->topDevice()->drawPaint(layer->paint());
1988 }
1989 }
1990
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1991 void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1992 const SkPaint& paint) {
1993 if ((long)count <= 0 || paint.nothingToDraw()) {
1994 return;
1995 }
1996 SkASSERT(pts != nullptr);
1997
1998 SkRect bounds;
1999 // Compute bounds from points (common for drawing a single line)
2000 if (count == 2) {
2001 bounds.set(pts[0], pts[1]);
2002 } else {
2003 bounds.setBounds(pts, SkToInt(count));
2004 }
2005
2006 // Enforce paint style matches implicit behavior of drawPoints
2007 SkPaint strokePaint = paint;
2008 strokePaint.setStyle(SkPaint::kStroke_Style);
2009 if (this->internalQuickReject(bounds, strokePaint)) {
2010 return;
2011 }
2012
2013 auto layer = this->aboutToDraw(this, strokePaint, &bounds);
2014 if (layer) {
2015 this->topDevice()->drawPoints(mode, count, pts, layer->paint());
2016 }
2017 }
2018
onDrawRect(const SkRect & r,const SkPaint & paint)2019 void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
2020 SkASSERT(r.isSorted());
2021 if (this->internalQuickReject(r, paint)) {
2022 return;
2023 }
2024
2025 auto layer = this->aboutToDraw(this, paint, &r, CheckForOverwrite::kYes);
2026 if (layer) {
2027 this->topDevice()->drawRect(r, layer->paint());
2028 }
2029 }
2030
onDrawRegion(const SkRegion & region,const SkPaint & paint)2031 void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2032 const SkRect bounds = SkRect::Make(region.getBounds());
2033 if (this->internalQuickReject(bounds, paint)) {
2034 return;
2035 }
2036
2037 auto layer = this->aboutToDraw(this, paint, &bounds);
2038 if (layer) {
2039 this->topDevice()->drawRegion(region, layer->paint());
2040 }
2041 }
2042
onDrawBehind(const SkPaint & paint)2043 void SkCanvas::onDrawBehind(const SkPaint& paint) {
2044 SkBaseDevice* dev = this->topDevice();
2045 if (!dev) {
2046 return;
2047 }
2048
2049 SkIRect bounds;
2050 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2051 for (;;) {
2052 const MCRec* rec = (const MCRec*)iter.prev();
2053 if (!rec) {
2054 return; // no backimages, so nothing to draw
2055 }
2056 if (rec->fBackImage) {
2057 // drawBehind should only have been called when the saveBehind record is active;
2058 // if this fails, it means a real saveLayer was made w/o being restored first.
2059 SkASSERT(dev == rec->fDevice);
2060 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2061 rec->fBackImage->fImage->width(),
2062 rec->fBackImage->fImage->height());
2063 break;
2064 }
2065 }
2066
2067 // The backimage location (and thus bounds) were defined in the device's space, so mark it
2068 // as a clip. We use a clip instead of just drawing a rect in case the paint has an image
2069 // filter on it (which is applied before any auto-layer so the filter is clipped).
2070 dev->save();
2071 {
2072 // We also have to temporarily whack the device matrix since clipRegion is affected by the
2073 // global-to-device matrix and clipRect is affected by the local-to-device.
2074 SkAutoDeviceTransformRestore adtr(dev, SkMatrix::I());
2075 dev->clipRect(SkRect::Make(bounds), SkClipOp::kIntersect, /* aa */ false);
2076 // ~adtr will reset the local-to-device matrix so that drawPaint() shades correctly.
2077 }
2078
2079 auto layer = this->aboutToDraw(this, paint);
2080 if (layer) {
2081 this->topDevice()->drawPaint(layer->paint());
2082 }
2083
2084 dev->restore(fMCRec->fMatrix);
2085 }
2086
onDrawOval(const SkRect & oval,const SkPaint & paint)2087 void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
2088 SkASSERT(oval.isSorted());
2089 if (this->internalQuickReject(oval, paint)) {
2090 return;
2091 }
2092
2093 auto layer = this->aboutToDraw(this, paint, &oval);
2094 if (layer) {
2095 this->topDevice()->drawOval(oval, layer->paint());
2096 }
2097 }
2098
onDrawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)2099 void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2100 SkScalar sweepAngle, bool useCenter,
2101 const SkPaint& paint) {
2102 SkASSERT(oval.isSorted());
2103 if (this->internalQuickReject(oval, paint)) {
2104 return;
2105 }
2106
2107 auto layer = this->aboutToDraw(this, paint, &oval);
2108 if (layer) {
2109 this->topDevice()->drawArc(oval, startAngle, sweepAngle, useCenter, layer->paint());
2110 }
2111 }
2112
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)2113 void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
2114 const SkRect& bounds = rrect.getBounds();
2115
2116 // Delegating to simpler draw operations
2117 if (rrect.isRect()) {
2118 // call the non-virtual version
2119 this->SkCanvas::drawRect(bounds, paint);
2120 return;
2121 } else if (rrect.isOval()) {
2122 // call the non-virtual version
2123 this->SkCanvas::drawOval(bounds, paint);
2124 return;
2125 }
2126
2127 if (this->internalQuickReject(bounds, paint)) {
2128 return;
2129 }
2130
2131 auto layer = this->aboutToDraw(this, paint, &bounds);
2132 if (layer) {
2133 this->topDevice()->drawRRect(rrect, layer->paint());
2134 }
2135 }
2136
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)2137 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
2138 const SkRect& bounds = outer.getBounds();
2139 if (this->internalQuickReject(bounds, paint)) {
2140 return;
2141 }
2142
2143 auto layer = this->aboutToDraw(this, paint, &bounds);
2144 if (layer) {
2145 this->topDevice()->drawDRRect(outer, inner, layer->paint());
2146 }
2147 }
2148
onDrawPath(const SkPath & path,const SkPaint & paint)2149 void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
2150 #ifdef SK_ENABLE_STENCIL_CULLING_OHOS
2151 onDrawPathCommon(path, paint, false);
2152 }
2153
onDrawPathWithStencil(const SkPath & path,const SkPaint & paint,uint32_t stencilRef)2154 void SkCanvas::onDrawPathWithStencil(const SkPath& path, const SkPaint& paint, uint32_t stencilRef) {
2155 onDrawPathCommon(path, paint, true, stencilRef);
2156 }
2157
onDrawPathCommon(const SkPath & path,const SkPaint & paint,bool useStencil,uint32_t stencilRef)2158 void SkCanvas::onDrawPathCommon(const SkPath& path, const SkPaint& paint, bool useStencil, uint32_t stencilRef) {
2159 #endif
2160 if (!path.isFinite()) {
2161 return;
2162 }
2163
2164 const SkRect& pathBounds = path.getBounds();
2165 if (!path.isInverseFillType() && this->internalQuickReject(pathBounds, paint)) {
2166 return;
2167 }
2168 if (path.isInverseFillType() && pathBounds.width() <= 0 && pathBounds.height() <= 0) {
2169 this->internalDrawPaint(paint);
2170 return;
2171 }
2172
2173 auto layer = this->aboutToDraw(this, paint, &pathBounds);
2174 if (layer) {
2175 #ifdef SK_ENABLE_STENCIL_CULLING_OHOS
2176 if (useStencil) {
2177 this->topDevice()->drawPathWithStencil(path, layer->paint(), stencilRef);
2178 } else {
2179 this->topDevice()->drawPath(path, layer->paint());
2180 }
2181 #else
2182 this->topDevice()->drawPath(path, layer->paint());
2183 #endif
2184 }
2185 }
2186
canDrawBitmapAsSprite(SkScalar x,SkScalar y,int w,int h,const SkSamplingOptions & sampling,const SkPaint & paint)2187 bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h,
2188 const SkSamplingOptions& sampling, const SkPaint& paint) {
2189 if (!paint.getImageFilter()) {
2190 return false;
2191 }
2192
2193 const SkMatrix& ctm = this->getTotalMatrix();
2194 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), sampling, paint)) {
2195 return false;
2196 }
2197
2198 // The other paint effects need to be applied before the image filter, but the sprite draw
2199 // applies the filter explicitly first.
2200 if (paint.getAlphaf() < 1.f || paint.getColorFilter() || paint.getMaskFilter()) {
2201 return false;
2202 }
2203 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2204 // Once we can filter and the filter will return a result larger than itself, we should be
2205 // able to remove this constraint.
2206 // skbug.com/4526
2207 //
2208 SkPoint pt;
2209 ctm.mapXY(x, y, &pt);
2210 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2211 // quick bounds have been outset by 1px compared to overall device bounds, so this makes the
2212 // contains check equivalent to between ir and device bounds
2213 ir.outset(1, 1);
2214 return ir.contains(fQuickRejectBounds);
2215 }
2216
2217 // Clean-up the paint to match the drawing semantics for drawImage et al. (skbug.com/7804).
clean_paint_for_drawImage(const SkPaint * paint)2218 static SkPaint clean_paint_for_drawImage(const SkPaint* paint) {
2219 SkPaint cleaned;
2220 if (paint) {
2221 cleaned = *paint;
2222 cleaned.setStyle(SkPaint::kFill_Style);
2223 cleaned.setPathEffect(nullptr);
2224 }
2225 return cleaned;
2226 }
2227
2228 // drawVertices fills triangles and ignores mask filter and path effect,
2229 // so canonicalize the paint before checking quick reject.
clean_paint_for_drawVertices(SkPaint paint)2230 static SkPaint clean_paint_for_drawVertices(SkPaint paint) {
2231 paint.setStyle(SkPaint::kFill_Style);
2232 paint.setMaskFilter(nullptr);
2233 paint.setPathEffect(nullptr);
2234 return paint;
2235 }
2236
onDrawImage2(const SkImage * image,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)2237 void SkCanvas::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y,
2238 const SkSamplingOptions& sampling, const SkPaint* paint) {
2239 #ifdef SK_ENABLE_STENCIL_CULLING_OHOS
2240 drawImageCommon(image, x, y, sampling, paint, false);
2241 }
onDrawImage2WithStencil(const SkImage * image,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint,uint32_t stencilRef)2242 void SkCanvas::onDrawImage2WithStencil(const SkImage* image, SkScalar x, SkScalar y,
2243 const SkSamplingOptions& sampling, const SkPaint* paint, uint32_t stencilRef) {
2244 TRACE_EVENT0("skia", TRACE_FUNC);
2245 drawImageCommon(image, x, y, sampling, paint, true, stencilRef);
2246 }
drawImageCommon(const SkImage * image,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint,bool useStencil,uint32_t stencilRef)2247 void SkCanvas::drawImageCommon(const SkImage* image, SkScalar x, SkScalar y,
2248 const SkSamplingOptions& sampling, const SkPaint* paint, bool useStencil,
2249 uint32_t stencilRef) {
2250 #endif
2251 SkPaint realPaint = clean_paint_for_drawImage(paint);
2252
2253 SkRect bounds = SkRect::MakeXYWH(x, y, image->width(), image->height());
2254 if (this->internalQuickReject(bounds, realPaint)) {
2255 return;
2256 }
2257
2258 if (realPaint.getImageFilter() &&
2259 this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), sampling, realPaint) &&
2260 !image_to_color_filter(&realPaint)) {
2261 // Evaluate the image filter directly on the input image and then draw the result, instead
2262 // of first drawing the image to a temporary layer and filtering.
2263 SkBaseDevice* device = this->topDevice();
2264 sk_sp<SkSpecialImage> special;
2265 if ((special = device->makeSpecial(image))) {
2266 sk_sp<SkImageFilter> filter = realPaint.refImageFilter();
2267 realPaint.setImageFilter(nullptr);
2268
2269 // TODO(michaelludwig) - Many filters could probably be evaluated like this even if the
2270 // CTM is not translate-only; the post-transformation of the filtered image by the CTM
2271 // will probably look just as good and not require an extra layer.
2272 // TODO(michaelludwig) - Once image filter implementations can support source images
2273 // with non-(0,0) origins, we can just mark the origin as (x,y) instead of doing a
2274 // pre-concat here.
2275 SkMatrix layerToDevice = device->localToDevice();
2276 layerToDevice.preTranslate(x, y);
2277 skif::Mapping mapping(layerToDevice, SkMatrix::Translate(-x, -y));
2278
2279 if (this->predrawNotify()) {
2280 device->drawFilteredImage(mapping, special.get(), filter.get(), sampling,realPaint);
2281 }
2282 return;
2283 } // else fall through to regular drawing path
2284 }
2285
2286 auto layer = this->aboutToDraw(this, realPaint, &bounds);
2287 if (layer) {
2288 #ifdef SK_ENABLE_STENCIL_CULLING_OHOS
2289 if (useStencil) {
2290 this->topDevice()->drawImageRectWithStencil(image, nullptr, bounds, sampling,
2291 layer->paint(), kStrict_SrcRectConstraint, stencilRef);
2292 } else {
2293 this->topDevice()->drawImageRect(image, nullptr, bounds, sampling,
2294 layer->paint(), kStrict_SrcRectConstraint);
2295 }
2296 #else
2297 this->topDevice()->drawImageRect(image, nullptr, bounds, sampling,
2298 layer->paint(), kStrict_SrcRectConstraint);
2299 #endif
2300 }
2301 }
2302
onDrawImageRect2(const SkImage * image,const SkRect & src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)2303 void SkCanvas::onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst,
2304 const SkSamplingOptions& sampling, const SkPaint* paint,
2305 SrcRectConstraint constraint) {
2306 SkPaint realPaint = clean_paint_for_drawImage(paint);
2307
2308 if (this->internalQuickReject(dst, realPaint)) {
2309 return;
2310 }
2311
2312 auto layer = this->aboutToDraw(this, realPaint, &dst, CheckForOverwrite::kYes,
2313 image->isOpaque() ? kOpaque_ShaderOverrideOpacity
2314 : kNotOpaque_ShaderOverrideOpacity);
2315 if (layer) {
2316 this->topDevice()->drawImageRect(image, &src, dst, sampling, layer->paint(), constraint);
2317 }
2318 }
2319
onDrawImageLattice2(const SkImage * image,const Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)2320 void SkCanvas::onDrawImageLattice2(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2321 SkFilterMode filter, const SkPaint* paint) {
2322 SkPaint realPaint = clean_paint_for_drawImage(paint);
2323
2324 if (this->internalQuickReject(dst, realPaint)) {
2325 return;
2326 }
2327
2328 auto layer = this->aboutToDraw(this, realPaint, &dst);
2329 if (layer) {
2330 this->topDevice()->drawImageLattice(image, lattice, dst, filter, layer->paint());
2331 }
2332 }
2333
drawImage(const SkImage * image,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)2334 void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y,
2335 const SkSamplingOptions& sampling, const SkPaint* paint) {
2336 TRACE_EVENT0("skia", TRACE_FUNC);
2337 RETURN_ON_NULL(image);
2338 this->onDrawImage2(image, x, y, sampling, paint);
2339 }
2340
drawImageRect(const SkImage * image,const SkRect & src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)2341 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
2342 const SkSamplingOptions& sampling, const SkPaint* paint,
2343 SrcRectConstraint constraint) {
2344 RETURN_ON_NULL(image);
2345 if (!fillable(dst) || !fillable(src)) {
2346 return;
2347 }
2348 this->onDrawImageRect2(image, src, dst, sampling, paint, constraint);
2349 }
2350
drawImageRect(const SkImage * image,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint)2351 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst,
2352 const SkSamplingOptions& sampling, const SkPaint* paint) {
2353 RETURN_ON_NULL(image);
2354 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, sampling,
2355 paint, kFast_SrcRectConstraint);
2356 }
2357
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2358 void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2359 const SkPaint& paint) {
2360 auto glyphRunList = fScratchGlyphRunBuilder->blobToGlyphRunList(*blob, {x, y});
2361 this->onDrawGlyphRunList(glyphRunList, paint);
2362 }
2363
onDrawGlyphRunList(const SkGlyphRunList & glyphRunList,const SkPaint & paint)2364 void SkCanvas::onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) {
2365 SkRect bounds = glyphRunList.sourceBounds();
2366 if (this->internalQuickReject(bounds, paint)) {
2367 return;
2368 }
2369 auto layer = this->aboutToDraw(this, paint, &bounds);
2370 if (layer) {
2371 this->topDevice()->drawGlyphRunList(glyphRunList, layer->paint());
2372 }
2373 }
2374
2375 // These call the (virtual) onDraw... method
drawSimpleText(const void * text,size_t byteLength,SkTextEncoding encoding,SkScalar x,SkScalar y,const SkFont & font,const SkPaint & paint)2376 void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
2377 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2378 TRACE_EVENT0("skia", TRACE_FUNC);
2379 if (byteLength) {
2380 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
2381 const SkGlyphRunList& glyphRunList =
2382 fScratchGlyphRunBuilder->textToGlyphRunList(
2383 font, paint, text, byteLength, {x, y}, encoding);
2384 if (!glyphRunList.empty()) {
2385 this->onDrawGlyphRunList(glyphRunList, paint);
2386 }
2387 }
2388 }
2389
drawGlyphs(int count,const SkGlyphID * glyphs,const SkPoint * positions,const uint32_t * clusters,int textByteCount,const char * utf8text,SkPoint origin,const SkFont & font,const SkPaint & paint)2390 void SkCanvas::drawGlyphs(int count, const SkGlyphID* glyphs, const SkPoint* positions,
2391 const uint32_t* clusters, int textByteCount, const char* utf8text,
2392 SkPoint origin, const SkFont& font, const SkPaint& paint) {
2393 if (count <= 0) { return; }
2394
2395 SkGlyphRun glyphRun {
2396 font,
2397 SkMakeSpan(positions, count),
2398 SkMakeSpan(glyphs, count),
2399 SkMakeSpan(utf8text, textByteCount),
2400 SkMakeSpan(clusters, count),
2401 SkSpan<SkVector>()
2402 };
2403 SkGlyphRunList glyphRunList {
2404 glyphRun,
2405 glyphRun.sourceBounds(paint).makeOffset(origin),
2406 origin
2407 };
2408 this->onDrawGlyphRunList(glyphRunList, paint);
2409 }
2410
drawGlyphs(int count,const SkGlyphID glyphs[],const SkPoint positions[],SkPoint origin,const SkFont & font,const SkPaint & paint)2411 void SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[],
2412 SkPoint origin, const SkFont& font, const SkPaint& paint) {
2413 if (count <= 0) { return; }
2414
2415 SkGlyphRun glyphRun {
2416 font,
2417 SkMakeSpan(positions, count),
2418 SkMakeSpan(glyphs, count),
2419 SkSpan<const char>(),
2420 SkSpan<const uint32_t>(),
2421 SkSpan<SkVector>()
2422 };
2423 SkGlyphRunList glyphRunList {
2424 glyphRun,
2425 glyphRun.sourceBounds(paint).makeOffset(origin),
2426 origin
2427 };
2428 this->onDrawGlyphRunList(glyphRunList, paint);
2429 }
2430
drawGlyphs(int count,const SkGlyphID glyphs[],const SkRSXform xforms[],SkPoint origin,const SkFont & font,const SkPaint & paint)2431 void SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkRSXform xforms[],
2432 SkPoint origin, const SkFont& font, const SkPaint& paint) {
2433 if (count <= 0) { return; }
2434
2435 auto [positions, rotateScales] =
2436 fScratchGlyphRunBuilder->convertRSXForm(SkMakeSpan(xforms, count));
2437
2438 SkGlyphRun glyphRun {
2439 font,
2440 positions,
2441 SkMakeSpan(glyphs, count),
2442 SkSpan<const char>(),
2443 SkSpan<const uint32_t>(),
2444 rotateScales
2445 };
2446 SkGlyphRunList glyphRunList {
2447 glyphRun,
2448 glyphRun.sourceBounds(paint).makeOffset(origin),
2449 origin
2450 };
2451 this->onDrawGlyphRunList(glyphRunList, paint);
2452 }
2453
drawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2454 void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2455 const SkPaint& paint) {
2456 TRACE_EVENT0("skia", TRACE_FUNC);
2457 RETURN_ON_NULL(blob);
2458 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
2459
2460 // Overflow if more than 2^21 glyphs stopping a buffer overflow latter in the stack.
2461 // See chromium:1080481
2462 // TODO: can consider unrolling a few at a time if this limit becomes a problem.
2463 int totalGlyphCount = 0;
2464 constexpr int kMaxGlyphCount = 1 << 21;
2465 SkTextBlob::Iter i(*blob);
2466 SkTextBlob::Iter::Run r;
2467 while (i.next(&r)) {
2468 int glyphsLeft = kMaxGlyphCount - totalGlyphCount;
2469 RETURN_ON_FALSE(r.fGlyphCount <= glyphsLeft);
2470 totalGlyphCount += r.fGlyphCount;
2471 }
2472 this->onDrawTextBlob(blob, x, y, paint);
2473 }
2474
onDrawVerticesObject(const SkVertices * vertices,SkBlendMode bmode,const SkPaint & paint)2475 void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2476 const SkPaint& paint) {
2477 SkPaint simplePaint = clean_paint_for_drawVertices(paint);
2478
2479 const SkRect& bounds = vertices->bounds();
2480 if (this->internalQuickReject(bounds, simplePaint)) {
2481 return;
2482 }
2483
2484 auto layer = this->aboutToDraw(this, simplePaint, &bounds);
2485 if (layer) {
2486 this->topDevice()->drawVertices(vertices, bmode, layer->paint());
2487 }
2488 }
2489
drawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)2490 void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2491 const SkPoint texCoords[4], SkBlendMode bmode,
2492 const SkPaint& paint) {
2493 TRACE_EVENT0("skia", TRACE_FUNC);
2494 if (nullptr == cubics) {
2495 return;
2496 }
2497
2498 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
2499 }
2500
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)2501 void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2502 const SkPoint texCoords[4], SkBlendMode bmode,
2503 const SkPaint& paint) {
2504 // drawPatch has the same behavior restrictions as drawVertices
2505 SkPaint simplePaint = clean_paint_for_drawVertices(paint);
2506
2507 // Since a patch is always within the convex hull of the control points, we discard it when its
2508 // bounding rectangle is completely outside the current clip.
2509 SkRect bounds;
2510 bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts);
2511 if (this->internalQuickReject(bounds, simplePaint)) {
2512 return;
2513 }
2514
2515 auto layer = this->aboutToDraw(this, simplePaint, &bounds);
2516 if (layer) {
2517 this->topDevice()->drawPatch(cubics, colors, texCoords, bmode, layer->paint());
2518 }
2519 }
2520
drawDrawable(SkDrawable * dr,SkScalar x,SkScalar y)2521 void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2522 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2523 TRACE_EVENT0("skia", TRACE_FUNC);
2524 #endif
2525 RETURN_ON_NULL(dr);
2526 if (x || y) {
2527 SkMatrix matrix = SkMatrix::Translate(x, y);
2528 this->onDrawDrawable(dr, &matrix);
2529 } else {
2530 this->onDrawDrawable(dr, nullptr);
2531 }
2532 }
2533
drawDrawable(SkDrawable * dr,const SkMatrix * matrix)2534 void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2535 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2536 TRACE_EVENT0("skia", TRACE_FUNC);
2537 #endif
2538 RETURN_ON_NULL(dr);
2539 if (matrix && matrix->isIdentity()) {
2540 matrix = nullptr;
2541 }
2542 this->onDrawDrawable(dr, matrix);
2543 }
2544
onDrawDrawable(SkDrawable * dr,const SkMatrix * matrix)2545 void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2546 // drawable bounds are no longer reliable (e.g. android displaylist)
2547 // so don't use them for quick-reject
2548 if (this->predrawNotify()) {
2549 this->topDevice()->drawDrawable(dr, matrix, this);
2550 }
2551 }
2552
onDrawAtlas2(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode bmode,const SkSamplingOptions & sampling,const SkRect * cull,const SkPaint * paint)2553 void SkCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2554 const SkColor colors[], int count, SkBlendMode bmode,
2555 const SkSamplingOptions& sampling, const SkRect* cull,
2556 const SkPaint* paint) {
2557 // drawAtlas is a combination of drawVertices and drawImage...
2558 SkPaint realPaint = clean_paint_for_drawVertices(clean_paint_for_drawImage(paint));
2559 realPaint.setShader(atlas->makeShader(sampling));
2560
2561 if (cull && this->internalQuickReject(*cull, realPaint)) {
2562 return;
2563 }
2564
2565 auto layer = this->aboutToDraw(this, realPaint);
2566 if (layer) {
2567 this->topDevice()->drawAtlas(xform, tex, colors, count, bmode, layer->paint());
2568 }
2569 }
2570
onDrawAnnotation(const SkRect & rect,const char key[],SkData * value)2571 void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2572 SkASSERT(key);
2573
2574 if (this->predrawNotify()) {
2575 this->topDevice()->drawAnnotation(rect, key, value);
2576 }
2577 }
2578
onDrawEdgeAAQuad(const SkRect & r,const SkPoint clip[4],QuadAAFlags edgeAA,const SkColor4f & color,SkBlendMode mode)2579 void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2580 const SkColor4f& color, SkBlendMode mode) {
2581 SkASSERT(r.isSorted());
2582
2583 SkPaint paint{color};
2584 paint.setBlendMode(mode);
2585 if (this->internalQuickReject(r, paint)) {
2586 return;
2587 }
2588
2589 if (this->predrawNotify()) {
2590 this->topDevice()->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2591 }
2592 }
2593
onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)2594 void SkCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count,
2595 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2596 const SkSamplingOptions& sampling, const SkPaint* paint,
2597 SrcRectConstraint constraint) {
2598 if (count <= 0) {
2599 // Nothing to draw
2600 return;
2601 }
2602
2603 SkPaint realPaint = clean_paint_for_drawImage(paint);
2604
2605 // We could calculate the set's dstRect union to always check quickReject(), but we can't reject
2606 // individual entries and Chromium's occlusion culling already makes it likely that at least one
2607 // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1),
2608 // or we need it for the autolooper (since it greatly improves image filter perf).
2609 bool needsAutoLayer = SkToBool(realPaint.getImageFilter());
2610 bool setBoundsValid = count == 1 || needsAutoLayer;
2611 SkRect setBounds = imageSet[0].fDstRect;
2612 if (imageSet[0].fMatrixIndex >= 0) {
2613 // Account for the per-entry transform that is applied prior to the CTM when drawing
2614 preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds);
2615 }
2616 if (needsAutoLayer) {
2617 for (int i = 1; i < count; ++i) {
2618 SkRect entryBounds = imageSet[i].fDstRect;
2619 if (imageSet[i].fMatrixIndex >= 0) {
2620 preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds);
2621 }
2622 setBounds.joinPossiblyEmptyRect(entryBounds);
2623 }
2624 }
2625
2626 // If we happen to have the draw bounds, though, might as well check quickReject().
2627 if (setBoundsValid && this->internalQuickReject(setBounds, realPaint)) {
2628 return;
2629 }
2630
2631 auto layer = this->aboutToDraw(this, realPaint, setBoundsValid ? &setBounds : nullptr);
2632 if (layer) {
2633 this->topDevice()->drawEdgeAAImageSet(imageSet, count, dstClips, preViewMatrices, sampling,
2634 layer->paint(), constraint);
2635 }
2636 }
2637
2638 //////////////////////////////////////////////////////////////////////////////
2639 // These methods are NOT virtual, and therefore must call back into virtual
2640 // methods, rather than actually drawing themselves.
2641 //////////////////////////////////////////////////////////////////////////////
2642
drawColor(const SkColor4f & c,SkBlendMode mode)2643 void SkCanvas::drawColor(const SkColor4f& c, SkBlendMode mode) {
2644 SkPaint paint;
2645 paint.setColor(c);
2646 paint.setBlendMode(mode);
2647 this->drawPaint(paint);
2648 }
2649
drawPoint(SkScalar x,SkScalar y,const SkPaint & paint)2650 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2651 const SkPoint pt = { x, y };
2652 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2653 }
2654
drawLine(SkScalar x0,SkScalar y0,SkScalar x1,SkScalar y1,const SkPaint & paint)2655 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
2656 SkPoint pts[2];
2657 pts[0].set(x0, y0);
2658 pts[1].set(x1, y1);
2659 this->drawPoints(kLines_PointMode, 2, pts, paint);
2660 }
2661
drawCircle(SkScalar cx,SkScalar cy,SkScalar radius,const SkPaint & paint)2662 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
2663 if (radius < 0) {
2664 radius = 0;
2665 }
2666
2667 SkRect r;
2668 r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
2669 this->drawOval(r, paint);
2670 }
2671
drawRoundRect(const SkRect & r,SkScalar rx,SkScalar ry,const SkPaint & paint)2672 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2673 const SkPaint& paint) {
2674 if (rx > 0 && ry > 0) {
2675 SkRRect rrect;
2676 rrect.setRectXY(r, rx, ry);
2677 this->drawRRect(rrect, paint);
2678 } else {
2679 this->drawRect(r, paint);
2680 }
2681 }
2682
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)2683 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2684 SkScalar sweepAngle, bool useCenter,
2685 const SkPaint& paint) {
2686 TRACE_EVENT0("skia", TRACE_FUNC);
2687 if (oval.isEmpty() || !sweepAngle) {
2688 return;
2689 }
2690 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
2691 }
2692
2693 ///////////////////////////////////////////////////////////////////////////////
2694 #ifdef SK_DISABLE_SKPICTURE
drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2695 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
2696
2697
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2698 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2699 const SkPaint* paint) {}
2700 #else
2701
drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2702 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2703 TRACE_EVENT0("skia", TRACE_FUNC);
2704 RETURN_ON_NULL(picture);
2705
2706 if (matrix && matrix->isIdentity()) {
2707 matrix = nullptr;
2708 }
2709 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2710 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2711 picture->playback(this);
2712 } else {
2713 this->onDrawPicture(picture, matrix, paint);
2714 }
2715 }
2716
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2717 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2718 const SkPaint* paint) {
2719 if (this->internalQuickReject(picture->cullRect(), paint ? *paint : SkPaint{}, matrix)) {
2720 return;
2721 }
2722
2723 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2724 picture->playback(this);
2725 }
2726 #endif
2727
2728 ///////////////////////////////////////////////////////////////////////////////
2729
2730 SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2731 SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2732 SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2733 SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2734
ImageSetEntry(sk_sp<const SkImage> image,const SkRect & srcRect,const SkRect & dstRect,int matrixIndex,float alpha,unsigned aaFlags,bool hasClip)2735 SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2736 const SkRect& dstRect, int matrixIndex, float alpha,
2737 unsigned aaFlags, bool hasClip)
2738 : fImage(std::move(image))
2739 , fSrcRect(srcRect)
2740 , fDstRect(dstRect)
2741 , fMatrixIndex(matrixIndex)
2742 , fAlpha(alpha)
2743 , fAAFlags(aaFlags)
2744 , fHasClip(hasClip) {}
2745
ImageSetEntry(sk_sp<const SkImage> image,const SkRect & srcRect,const SkRect & dstRect,float alpha,unsigned aaFlags)2746 SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2747 const SkRect& dstRect, float alpha, unsigned aaFlags)
2748 : fImage(std::move(image))
2749 , fSrcRect(srcRect)
2750 , fDstRect(dstRect)
2751 , fAlpha(alpha)
2752 , fAAFlags(aaFlags) {}
2753
2754 ///////////////////////////////////////////////////////////////////////////////
2755
MakeRasterDirect(const SkImageInfo & info,void * pixels,size_t rowBytes,const SkSurfaceProps * props)2756 std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
2757 size_t rowBytes, const SkSurfaceProps* props) {
2758 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
2759 return nullptr;
2760 }
2761
2762 SkBitmap bitmap;
2763 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2764 return nullptr;
2765 }
2766
2767 return props ?
2768 std::make_unique<SkCanvas>(bitmap, *props) :
2769 std::make_unique<SkCanvas>(bitmap);
2770 }
2771
2772 ///////////////////////////////////////////////////////////////////////////////
2773
SkNoDrawCanvas(int width,int height)2774 SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2775 : INHERITED(SkIRect::MakeWH(width, height)) {}
2776
SkNoDrawCanvas(const SkIRect & bounds)2777 SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2778 : INHERITED(bounds) {}
2779
SkNoDrawCanvas(sk_sp<SkBaseDevice> device)2780 SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
2781 : INHERITED(device) {}
2782
getSaveLayerStrategy(const SaveLayerRec & rec)2783 SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2784 (void)this->INHERITED::getSaveLayerStrategy(rec);
2785 return kNoLayer_SaveLayerStrategy;
2786 }
2787
onDoSaveBehind(const SkRect *)2788 bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2789 return false;
2790 }
2791
2792 ///////////////////////////////////////////////////////////////////////////////
2793
2794 static_assert((int)SkRegion::kDifference_Op == (int)SkClipOp::kDifference, "");
2795 static_assert((int)SkRegion::kIntersect_Op == (int)SkClipOp::kIntersect, "");
2796
2797 ///////////////////////////////////////////////////////////////////////////////////////////////////
2798
accessTopRasterHandle() const2799 SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2800 const SkBaseDevice* dev = this->topDevice();
2801 if (fAllocator) {
2802 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2803 SkIRect clip = dev->devClipBounds();
2804 if (!clip.intersect({0, 0, dev->width(), dev->height()})) {
2805 clip.setEmpty();
2806 }
2807
2808 fAllocator->updateHandle(handle, dev->localToDevice(), clip);
2809 return handle;
2810 }
2811 return nullptr;
2812 }
2813
install(SkBitmap * bm,const SkImageInfo & info,const SkRasterHandleAllocator::Rec & rec)2814 static bool install(SkBitmap* bm, const SkImageInfo& info,
2815 const SkRasterHandleAllocator::Rec& rec) {
2816 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
2817 }
2818
allocBitmap(const SkImageInfo & info,SkBitmap * bm)2819 SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2820 SkBitmap* bm) {
2821 SkRasterHandleAllocator::Rec rec;
2822 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2823 return nullptr;
2824 }
2825 return rec.fHandle;
2826 }
2827
2828 std::unique_ptr<SkCanvas>
MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,const SkImageInfo & info,const Rec * rec)2829 SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2830 const SkImageInfo& info, const Rec* rec) {
2831 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
2832 return nullptr;
2833 }
2834
2835 SkBitmap bm;
2836 Handle hndl;
2837
2838 if (rec) {
2839 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2840 } else {
2841 hndl = alloc->allocBitmap(info, &bm);
2842 }
2843 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2844 }
2845
CalcHpsBluredImageDimension(const SkBlurArg & blurArg)2846 std::array<int, 2> SkCanvas::CalcHpsBluredImageDimension(const SkBlurArg& blurArg)
2847 {
2848 #if SK_SUPPORT_GPU
2849 auto dContext = GrAsDirectContext(this->recordingContext());
2850 if (dContext) {
2851 return dContext->CalcHpsBluredImageDimension(blurArg);
2852 }
2853 #endif
2854 return {0, 0};
2855 }
2856
onDrawBlurImage(const SkImage * image,const SkBlurArg & blurArg)2857 bool SkCanvas::onDrawBlurImage(const SkImage* image, const SkBlurArg& blurArg)
2858 {
2859 return this->topDevice()->drawBlurImage(image, blurArg);
2860 }
2861
2862 ///////////////////////////////////////////////////////////////////////////////////////////////////
2863