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