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/SkColorFilter.h"
11#include "include/core/SkImage.h"
12#include "include/core/SkImageFilter.h"
13#include "include/core/SkPathEffect.h"
14#include "include/core/SkPicture.h"
15#include "include/core/SkRRect.h"
16#include "include/core/SkRasterHandleAllocator.h"
17#include "include/core/SkString.h"
18#include "include/core/SkTextBlob.h"
19#include "include/core/SkVertices.h"
20#include "include/effects/SkRuntimeEffect.h"
21#include "include/private/SkNx.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/SkCanvasMatrix.h"
27#include "src/core/SkCanvasPriv.h"
28#include "src/core/SkClipOpPriv.h"
29#include "src/core/SkClipStack.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 <new>
51
52#if SK_SUPPORT_GPU
53#include "include/gpu/GrContext.h"
54#include "src/gpu/SkGr.h"
55#endif
56
57#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
58#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
59
60// This is a test: static_assert with no message is a c++17 feature,
61// and std::max() is constexpr only since the c++14 stdlib.
62static_assert(std::max(3,4) == 4);
63
64///////////////////////////////////////////////////////////////////////////////////////////////////
65
66/*
67 * Return true if the drawing this rect would hit every pixels in the canvas.
68 *
69 * Returns false if
70 * - rect does not contain the canvas' bounds
71 * - paint is not fill
72 * - paint would blur or otherwise change the coverage of the rect
73 */
74bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
75 ShaderOverrideOpacity overrideOpacity) const {
76 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
77 (int)kNone_ShaderOverrideOpacity,
78 "need_matching_enums0");
79 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
80 (int)kOpaque_ShaderOverrideOpacity,
81 "need_matching_enums1");
82 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
83 (int)kNotOpaque_ShaderOverrideOpacity,
84 "need_matching_enums2");
85
86 const SkISize size = this->getBaseLayerSize();
87 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
88
89 // if we're clipped at all, we can't overwrite the entire surface
90 {
91 SkBaseDevice* base = this->getDevice();
92 SkBaseDevice* top = this->getTopDevice();
93 if (base != top) {
94 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
95 }
96 if (!base->clipIsWideOpen()) {
97 return false;
98 }
99 }
100
101 if (rect) {
102 if (!this->getTotalMatrix().isScaleTranslate()) {
103 return false; // conservative
104 }
105
106 SkRect devRect;
107 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
108 if (!devRect.contains(bounds)) {
109 return false;
110 }
111 }
112
113 if (paint) {
114 SkPaint::Style paintStyle = paint->getStyle();
115 if (!(paintStyle == SkPaint::kFill_Style ||
116 paintStyle == SkPaint::kStrokeAndFill_Style)) {
117 return false;
118 }
119 if (paint->getMaskFilter() || paint->getPathEffect() || paint->getImageFilter()) {
120 return false; // conservative
121 }
122 }
123 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
124}
125
126///////////////////////////////////////////////////////////////////////////////////////////////////
127
128// experimental for faster tiled drawing...
129//#define SK_TRACE_SAVERESTORE
130
131#ifdef SK_TRACE_SAVERESTORE
132 static int gLayerCounter;
133 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
134 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
135
136 static int gRecCounter;
137 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
138 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
139
140 static int gCanvasCounter;
141 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
142 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
143#else
144 #define inc_layer()
145 #define dec_layer()
146 #define inc_rec()
147 #define dec_rec()
148 #define inc_canvas()
149 #define dec_canvas()
150#endif
151
152typedef SkTLazy<SkPaint> SkLazyPaint;
153
154void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
155 if (fSurfaceBase) {
156 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
157 ? SkSurface::kDiscard_ContentChangeMode
158 : SkSurface::kRetain_ContentChangeMode);
159 }
160}
161
162void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
163 ShaderOverrideOpacity overrideOpacity) {
164 if (fSurfaceBase) {
165 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
166 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
167 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
168 // and therefore we don't care which mode we're in.
169 //
170 if (fSurfaceBase->outstandingImageSnapshot()) {
171 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
172 mode = SkSurface::kDiscard_ContentChangeMode;
173 }
174 }
175 fSurfaceBase->aboutToDraw(mode);
176 }
177}
178
179///////////////////////////////////////////////////////////////////////////////
180
181/* This is the record we keep for each SkBaseDevice that the user installs.
182 The clip/matrix/proc are fields that reflect the top of the save/restore
183 stack. Whenever the canvas changes, it marks a dirty flag, and then before
184 these are used (assuming we're not on a layer) we rebuild these cache
185 values: they reflect the top of the save stack, but translated and clipped
186 by the device's XY offset and bitmap-bounds.
187*/
188struct DeviceCM {
189 DeviceCM* fNext;
190 sk_sp<SkBaseDevice> fDevice;
191 SkRasterClip fClip;
192 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
193 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
194 sk_sp<SkImage> fClipImage;
195 SkMatrix fClipMatrix;
196
197 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
198 const SkImage* clipImage, const SkMatrix* clipMatrix)
199 : fNext(nullptr)
200 , fDevice(std::move(device))
201 , fPaint(paint ? std::make_unique<SkPaint>(*paint) : nullptr)
202 , fStashedMatrix(stashed)
203 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
204 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
205 {}
206
207 void reset(const SkIRect& bounds) {
208 SkASSERT(!fPaint);
209 SkASSERT(!fNext);
210 SkASSERT(fDevice);
211 fClip.setRect(bounds);
212 }
213};
214
215namespace {
216// Encapsulate state needed to restore from saveBehind()
217struct BackImage {
218 sk_sp<SkSpecialImage> fImage;
219 SkIPoint fLoc;
220};
221}
222
223/* This is the record we keep for each save/restore level in the stack.
224 Since a level optionally copies the matrix and/or stack, we have pointers
225 for these fields. If the value is copied for this level, the copy is
226 stored in the ...Storage field, and the pointer points to that. If the
227 value is not copied for this level, we ignore ...Storage, and just point
228 at the corresponding value in the previous level in the stack.
229*/
230class SkCanvas::MCRec {
231public:
232 DeviceCM* fLayer;
233 /* If there are any layers in the stack, this points to the top-most
234 one that is at or below this level in the stack (so we know what
235 bitmap/device to draw into from this level. This value is NOT
236 reference counted, since the real owner is either our fLayer field,
237 or a previous one in a lower level.)
238 */
239 DeviceCM* fTopLayer;
240 std::unique_ptr<BackImage> fBackImage;
241 SkConservativeClip fRasterClip;
242 SkCanvasMatrix fMatrix;
243 int fDeferredSaveCount;
244
245 MCRec() {
246 fLayer = nullptr;
247 fTopLayer = nullptr;
248 fMatrix.reset();
249 fDeferredSaveCount = 0;
250
251 // don't bother initializing fNext
252 inc_rec();
253 }
254 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
255 fLayer = nullptr;
256 fTopLayer = prev.fTopLayer;
257 fDeferredSaveCount = 0;
258
259 // don't bother initializing fNext
260 inc_rec();
261 }
262 ~MCRec() {
263 delete fLayer;
264 dec_rec();
265 }
266
267 void reset(const SkIRect& bounds) {
268 SkASSERT(fLayer);
269 SkASSERT(fDeferredSaveCount == 0);
270
271 fMatrix.reset();
272 fRasterClip.setRect(bounds);
273 fLayer->reset(bounds);
274 }
275};
276
277class SkDrawIter {
278public:
279 SkDrawIter(SkCanvas* canvas)
280 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
281 {}
282
283 bool next() {
284 const DeviceCM* rec = fCurrLayer;
285 if (rec && rec->fDevice) {
286 fDevice = rec->fDevice.get();
287 fPaint = rec->fPaint.get();
288 fCurrLayer = rec->fNext;
289 // fCurrLayer may be nullptr now
290 return true;
291 }
292 return false;
293 }
294
295 const SkPaint* getPaint() const { return fPaint; }
296
297 SkBaseDevice* fDevice;
298
299private:
300 const DeviceCM* fCurrLayer;
301 const SkPaint* fPaint; // May be null.
302};
303
304#define FOR_EACH_TOP_DEVICE( code ) \
305 do { \
306 DeviceCM* layer = fMCRec->fTopLayer; \
307 while (layer) { \
308 SkBaseDevice* device = layer->fDevice.get(); \
309 if (device) { \
310 code; \
311 } \
312 layer = layer->fNext; \
313 } \
314 } while (0)
315
316/////////////////////////////////////////////////////////////////////////////
317
318/**
319 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
320 * colorfilter, else return nullptr.
321 */
322static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
323 SkImageFilter* imgf = paint.getImageFilter();
324 if (!imgf) {
325 return nullptr;
326 }
327
328 SkColorFilter* imgCFPtr;
329 if (!imgf->asAColorFilter(&imgCFPtr)) {
330 return nullptr;
331 }
332 sk_sp<SkColorFilter> imgCF(imgCFPtr);
333
334 SkColorFilter* paintCF = paint.getColorFilter();
335 if (nullptr == paintCF) {
336 // there is no existing paint colorfilter, so we can just return the imagefilter's
337 return imgCF;
338 }
339
340 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
341 // and we need to combine them into a single colorfilter.
342 return imgCF->makeComposed(sk_ref_sp(paintCF));
343}
344
345/**
346 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
347 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
348 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
349 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
350 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
351 * conservative "effective" bounds based on the settings in the paint... with one exception. This
352 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
353 * deliberately ignored.
354 */
355static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
356 const SkRect& rawBounds,
357 SkRect* storage) {
358 SkPaint tmpUnfiltered(paint);
359 tmpUnfiltered.setImageFilter(nullptr);
360 if (tmpUnfiltered.canComputeFastBounds()) {
361 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
362 } else {
363 return rawBounds;
364 }
365}
366
367class AutoLayerForImageFilter {
368public:
369 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
370 // paint. It's used to determine the size of the offscreen layer for filters.
371 // If null, the clip will be used instead.
372 AutoLayerForImageFilter(SkCanvas* canvas, const SkPaint& origPaint,
373 bool skipLayerForImageFilter = false,
374 const SkRect* rawBounds = nullptr) {
375 fCanvas = canvas;
376 fPaint = &origPaint;
377 fSaveCount = canvas->getSaveCount();
378 fTempLayerForImageFilter = false;
379
380 if (auto simplifiedCF = image_to_color_filter(origPaint)) {
381 SkASSERT(!fLazyPaint.isValid());
382 SkPaint* paint = fLazyPaint.set(origPaint);
383 paint->setColorFilter(std::move(simplifiedCF));
384 paint->setImageFilter(nullptr);
385 fPaint = paint;
386 }
387
388 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
389 /**
390 * We implement ImageFilters for a given draw by creating a layer, then applying the
391 * imagefilter to the pixels of that layer (its backing surface/image), and then
392 * we call restore() to xfer that layer to the main canvas.
393 *
394 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
395 * 2. Generate the src pixels:
396 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
397 * return (fPaint). We then draw the primitive (using srcover) into a cleared
398 * buffer/surface.
399 * 3. Restore the layer created in #1
400 * The imagefilter is passed the buffer/surface from the layer (now filled with the
401 * src pixels of the primitive). It returns a new "filtered" buffer, which we
402 * draw onto the previous layer using the xfermode from the original paint.
403 */
404
405 SkPaint restorePaint;
406 restorePaint.setImageFilter(fPaint->refImageFilter());
407 restorePaint.setBlendMode(fPaint->getBlendMode());
408
409 SkRect storage;
410 if (rawBounds) {
411 // Make rawBounds include all paint outsets except for those due to image filters.
412 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
413 }
414 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &restorePaint),
415 SkCanvas::kFullLayer_SaveLayerStrategy);
416 fTempLayerForImageFilter = true;
417
418 // Remove the restorePaint fields from our "working" paint
419 SkASSERT(!fLazyPaint.isValid());
420 SkPaint* paint = fLazyPaint.set(origPaint);
421 paint->setImageFilter(nullptr);
422 paint->setBlendMode(SkBlendMode::kSrcOver);
423 fPaint = paint;
424 }
425 }
426
427 ~AutoLayerForImageFilter() {
428 if (fTempLayerForImageFilter) {
429 fCanvas->internalRestore();
430 }
431 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
432 }
433
434 const SkPaint& paint() const {
435 SkASSERT(fPaint);
436 return *fPaint;
437 }
438
439private:
440 SkLazyPaint fLazyPaint; // base paint storage in case we need to modify it
441 SkCanvas* fCanvas;
442 const SkPaint* fPaint; // points to either the original paint, or lazy (if we needed it)
443 int fSaveCount;
444 bool fTempLayerForImageFilter;
445};
446
447////////// macros to place around the internal draw calls //////////////////
448
449#define DRAW_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
450 this->predrawNotify(); \
451 AutoLayerForImageFilter draw(this, paint, skipLayerForFilter, bounds); \
452 { SkDrawIter iter(this);
453
454
455#define DRAW_BEGIN_DRAWDEVICE(paint) \
456 this->predrawNotify(); \
457 AutoLayerForImageFilter draw(this, paint, true); \
458 { SkDrawIter iter(this);
459
460#define DRAW_BEGIN(paint, bounds) \
461 this->predrawNotify(); \
462 AutoLayerForImageFilter draw(this, paint, false, bounds); \
463 { SkDrawIter iter(this);
464
465#define DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
466 this->predrawNotify(bounds, &paint, auxOpaque); \
467 AutoLayerForImageFilter draw(this, paint, false, bounds); \
468 { SkDrawIter iter(this);
469
470#define DRAW_END }
471
472////////////////////////////////////////////////////////////////////////////
473
474static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
475 if (bounds.isEmpty()) {
476 return SkRect::MakeEmpty();
477 }
478
479 // Expand bounds out by 1 in case we are anti-aliasing. We store the
480 // bounds as floats to enable a faster quick reject implementation.
481 SkRect dst;
482 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
483 return dst;
484}
485
486void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
487 this->restoreToCount(1);
488 fMCRec->reset(bounds);
489
490 // We're peering through a lot of structs here. Only at this scope do we
491 // know that the device is a SkNoPixelsDevice.
492 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
493 fDeviceClipBounds = qr_clip_bounds(bounds);
494 fIsScaleTranslate = true;
495}
496
497void SkCanvas::init(sk_sp<SkBaseDevice> device) {
498 fSaveCount = 1;
499
500 fMCRec = (MCRec*)fMCStack.push_back();
501 new (fMCRec) MCRec;
502 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
503 fIsScaleTranslate = true;
504
505 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
506 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
507 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
508
509 fMCRec->fTopLayer = fMCRec->fLayer;
510
511 fSurfaceBase = nullptr;
512
513 if (device) {
514 // The root device and the canvas should always have the same pixel geometry
515 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
516 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
517 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
518
519 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
520 }
521
522 fScratchGlyphRunBuilder = std::make_unique<SkGlyphRunBuilder>();
523}
524
525SkCanvas::SkCanvas()
526 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
527 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
528{
529 inc_canvas();
530
531 this->init(nullptr);
532}
533
534SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
535 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
536 , fProps(SkSurfacePropsCopyOrDefault(props))
537{
538 inc_canvas();
539 this->init(sk_make_sp<SkNoPixelsDevice>(
540 SkIRect::MakeWH(std::max(width, 0), std::max(height, 0)), fProps));
541}
542
543SkCanvas::SkCanvas(const SkIRect& bounds)
544 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
545 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
546{
547 inc_canvas();
548
549 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
550 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
551}
552
553SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
554 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
555 , fProps(device->surfaceProps())
556{
557 inc_canvas();
558
559 this->init(device);
560}
561
562SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
563 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
564 , fProps(props)
565{
566 inc_canvas();
567
568 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
569 this->init(device);
570}
571
572SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
573 SkRasterHandleAllocator::Handle hndl)
574 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
575 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
576 , fAllocator(std::move(alloc))
577{
578 inc_canvas();
579
580 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
581 this->init(device);
582}
583
584SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
585
586#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
587SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
588 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
589 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
590 , fAllocator(nullptr)
591{
592 inc_canvas();
593
594 SkBitmap tmp(bitmap);
595 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
596 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
597 this->init(device);
598}
599#endif
600
601SkCanvas::~SkCanvas() {
602 // free up the contents of our deque
603 this->restoreToCount(1); // restore everything but the last
604
605 this->internalRestore(); // restore the last, since we're going away
606
607 dec_canvas();
608}
609
610///////////////////////////////////////////////////////////////////////////////
611
612void SkCanvas::flush() {
613 this->onFlush();
614}
615
616void SkCanvas::onFlush() {
617 SkBaseDevice* device = this->getDevice();
618 if (device) {
619 device->flush();
620 }
621}
622
623SkSurface* SkCanvas::getSurface() const {
624 return fSurfaceBase;
625}
626
627SkISize SkCanvas::getBaseLayerSize() const {
628 SkBaseDevice* d = this->getDevice();
629 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
630}
631
632SkIRect SkCanvas::getTopLayerBounds() const {
633 SkBaseDevice* d = this->getTopDevice();
634 if (!d) {
635 return SkIRect::MakeEmpty();
636 }
637 return d->getGlobalBounds();
638}
639
640SkBaseDevice* SkCanvas::getDevice() const {
641 // return root device
642 MCRec* rec = (MCRec*) fMCStack.front();
643 SkASSERT(rec && rec->fLayer);
644 return rec->fLayer->fDevice.get();
645}
646
647SkBaseDevice* SkCanvas::getTopDevice() const {
648 return fMCRec->fTopLayer->fDevice.get();
649}
650
651bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
652 SkBaseDevice* device = this->getDevice();
653 return device && pm.addr() && device->readPixels(pm, x, y);
654}
655
656bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
657 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
658}
659
660bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
661 SkPixmap pm;
662 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
663}
664
665bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
666 SkPixmap pm;
667 if (bitmap.peekPixels(&pm)) {
668 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
669 }
670 return false;
671}
672
673bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
674 int x, int y) {
675 SkBaseDevice* device = this->getDevice();
676 if (!device) {
677 return false;
678 }
679
680 // This check gives us an early out and prevents generation ID churn on the surface.
681 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
682 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
683 if (!srcRect.intersect({0, 0, device->width(), device->height()})) {
684 return false;
685 }
686
687 // Tell our owning surface to bump its generation ID.
688 const bool completeOverwrite =
689 srcRect.size() == SkISize::Make(device->width(), device->height());
690 this->predrawNotify(completeOverwrite);
691
692 // This can still fail, most notably in the case of a invalid color type or alpha type
693 // conversion. We could pull those checks into this function and avoid the unnecessary
694 // generation ID bump. But then we would be performing those checks twice, since they
695 // are also necessary at the bitmap/pixmap entry points.
696 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
697}
698
699//////////////////////////////////////////////////////////////////////////////
700
701void SkCanvas::checkForDeferredSave() {
702 if (fMCRec->fDeferredSaveCount > 0) {
703 this->doSave();
704 }
705}
706
707int SkCanvas::getSaveCount() const {
708#ifdef SK_DEBUG
709 int count = 0;
710 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
711 for (;;) {
712 const MCRec* rec = (const MCRec*)iter.next();
713 if (!rec) {
714 break;
715 }
716 count += 1 + rec->fDeferredSaveCount;
717 }
718 SkASSERT(count == fSaveCount);
719#endif
720 return fSaveCount;
721}
722
723int SkCanvas::save() {
724 fSaveCount += 1;
725 fMCRec->fDeferredSaveCount += 1;
726 return this->getSaveCount() - 1; // return our prev value
727}
728
729void SkCanvas::doSave() {
730 this->willSave();
731
732 SkASSERT(fMCRec->fDeferredSaveCount > 0);
733 fMCRec->fDeferredSaveCount -= 1;
734 this->internalSave();
735}
736
737void SkCanvas::restore() {
738 if (fMCRec->fDeferredSaveCount > 0) {
739 SkASSERT(fSaveCount > 1);
740 fSaveCount -= 1;
741 fMCRec->fDeferredSaveCount -= 1;
742 } else {
743 // check for underflow
744 if (fMCStack.count() > 1) {
745 this->willRestore();
746 SkASSERT(fSaveCount > 1);
747 fSaveCount -= 1;
748 this->internalRestore();
749 this->didRestore();
750 }
751 }
752}
753
754void SkCanvas::restoreToCount(int count) {
755 // sanity check
756 if (count < 1) {
757 count = 1;
758 }
759
760 int n = this->getSaveCount() - count;
761 for (int i = 0; i < n; ++i) {
762 this->restore();
763 }
764}
765
766void SkCanvas::internalSave() {
767 MCRec* newTop = (MCRec*)fMCStack.push_back();
768 new (newTop) MCRec(*fMCRec); // balanced in restore()
769 fMCRec = newTop;
770
771 FOR_EACH_TOP_DEVICE(device->save());
772}
773
774bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
775 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
776}
777
778bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
779 SkIRect* intersection, const SkImageFilter* imageFilter) {
780 // clipRectBounds() is called to determine the input layer size needed for a given image filter.
781 // The coordinate space of the rectangle passed to filterBounds(kReverse) is meant to be in the
782 // filtering layer space. Here, 'clipBounds' is always in the true device space. When an image
783 // filter does not require a decomposed CTM matrix, the filter space and device space are the
784 // same. When it has been decomposed, we want the original image filter node to process the
785 // bounds in the layer space represented by the decomposed scale matrix. 'imageFilter' is no
786 // longer the original filter, but has the remainder matrix baked into it, and passing in the
787 // the true device clip bounds ensures that the matrix image filter provides a layer clip bounds
788 // to the original filter node (barring inflation from consecutive calls to mapRect). While
789 // initially counter-intuitive given the apparent inconsistency of coordinate spaces, always
790 // passing getDeviceClipBounds() to 'imageFilter' is correct.
791 // FIXME (michaelludwig) - When the remainder matrix is instead applied as a final draw, it will
792 // be important to more accurately calculate the clip bounds in the layer space for the original
793 // image filter (similar to how matrix image filter does it, but ideally without the inflation).
794 SkIRect clipBounds = this->getDeviceClipBounds();
795 if (clipBounds.isEmpty()) {
796 return false;
797 }
798
799 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
800
801 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
802 // If the image filter DAG affects transparent black then we will need to render
803 // out to the clip bounds
804 bounds = nullptr;
805 }
806
807 SkIRect inputSaveLayerBounds;
808 if (bounds) {
809 SkRect r;
810 ctm.mapRect(&r, *bounds);
811 r.roundOut(&inputSaveLayerBounds);
812 } else { // no user bounds, so just use the clip
813 inputSaveLayerBounds = clipBounds;
814 }
815
816 if (imageFilter) {
817 // expand the clip bounds by the image filter DAG to include extra content that might
818 // be required by the image filters.
819 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
820 SkImageFilter::kReverse_MapDirection,
821 &inputSaveLayerBounds);
822 }
823
824 SkIRect clippedSaveLayerBounds;
825 if (bounds) {
826 // For better or for worse, user bounds currently act as a hard clip on the layer's
827 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
828 clippedSaveLayerBounds = inputSaveLayerBounds;
829 } else {
830 // If there are no user bounds, we don't want to artificially restrict the resulting
831 // layer bounds, so allow the expanded clip bounds free reign.
832 clippedSaveLayerBounds = clipBounds;
833 }
834
835 // early exit if the layer's bounds are clipped out
836 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
837 if (BoundsAffectsClip(saveLayerFlags)) {
838 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
839 fMCRec->fRasterClip.setEmpty();
840 fDeviceClipBounds.setEmpty();
841 }
842 return false;
843 }
844 SkASSERT(!clippedSaveLayerBounds.isEmpty());
845
846 if (BoundsAffectsClip(saveLayerFlags)) {
847 // Simplify the current clips since they will be applied properly during restore()
848 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
849 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
850 }
851
852 if (intersection) {
853 *intersection = clippedSaveLayerBounds;
854 }
855
856 return true;
857}
858
859int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
860 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
861}
862
863int SkCanvas::saveLayer(const SaveLayerRec& rec) {
864 TRACE_EVENT0("skia", TRACE_FUNC);
865 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
866 // no need for the layer (or any of the draws until the matching restore()
867 this->save();
868 this->clipRect({0,0,0,0});
869 } else {
870 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
871 fSaveCount += 1;
872 this->internalSaveLayer(rec, strategy);
873 }
874 return this->getSaveCount() - 1;
875}
876
877int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
878 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
879 // Assuming clips never expand, if the request bounds is outside of the current clip
880 // there is no need to copy/restore the area, so just devolve back to a regular save.
881 this->save();
882 } else {
883 bool doTheWork = this->onDoSaveBehind(bounds);
884 fSaveCount += 1;
885 this->internalSave();
886 if (doTheWork) {
887 this->internalSaveBehind(bounds);
888 }
889 }
890 return this->getSaveCount() - 1;
891}
892
893void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
894 SkBaseDevice* dst, const SkIPoint& dstOrigin,
895 const SkMatrix& ctm) {
896 // The local bounds of the src device; all the bounds passed to snapSpecial must be intersected
897 // with this rect.
898 const SkIRect srcDevRect = SkIRect::MakeWH(src->width(), src->height());
899 // TODO(michaelludwig) - Update this function to use the relative transforms between src and
900 // dst; for now, since devices never have complex transforms, we can keep using getOrigin().
901 if (!filter) {
902 // All non-filtered devices are currently axis aligned, so they only differ by their origin.
903 // This means that we only have to copy a dst-sized block of pixels out of src and translate
904 // it to the matching position relative to dst's origin.
905 SkIRect snapBounds = SkIRect::MakeXYWH(dstOrigin.x() - src->getOrigin().x(),
906 dstOrigin.y() - src->getOrigin().y(),
907 dst->width(), dst->height());
908 if (!snapBounds.intersect(srcDevRect)) {
909 return;
910 }
911
912 auto special = src->snapSpecial(snapBounds);
913 if (special) {
914 // The image is drawn at 1-1 scale with integer translation, so no filtering is needed.
915 SkPaint p;
916 dst->drawSpecial(special.get(), 0, 0, p, nullptr, SkMatrix::I());
917 }
918 return;
919 }
920
921 // First decompose the ctm into a post-filter transform and a filter matrix that is supported
922 // by the backdrop filter.
923 SkMatrix toRoot, layerMatrix;
924 SkSize scale;
925 if (ctm.isScaleTranslate() || as_IFB(filter)->canHandleComplexCTM()) {
926 toRoot = SkMatrix::I();
927 layerMatrix = ctm;
928 } else if (ctm.decomposeScale(&scale, &toRoot)) {
929 layerMatrix = SkMatrix::MakeScale(scale.fWidth, scale.fHeight);
930 } else {
931 // Perspective, for now, do no scaling of the layer itself.
932 // TODO (michaelludwig) - perhaps it'd be better to explore a heuristic scale pulled from
933 // the matrix, e.g. based on the midpoint of the near/far planes?
934 toRoot = ctm;
935 layerMatrix = SkMatrix::I();
936 }
937
938 // We have to map the dst bounds from the root space into the layer space where filtering will
939 // occur. If we knew the input bounds of the content that defined the original dst bounds, we
940 // could map that forward by layerMatrix and have tighter bounds, but toRoot^-1 * dst bounds
941 // is a safe, conservative estimate.
942 SkMatrix fromRoot;
943 if (!toRoot.invert(&fromRoot)) {
944 return;
945 }
946
947 // This represents what the backdrop filter needs to produce in the layer space, and is sized
948 // such that drawing it into dst with the toRoot transform will cover the actual dst device.
949 SkIRect layerTargetBounds = fromRoot.mapRect(
950 SkRect::MakeXYWH(dstOrigin.x(), dstOrigin.y(), dst->width(), dst->height())).roundOut();
951 // While layerTargetBounds is what needs to be output by the filter, the filtering process may
952 // require some extra input pixels.
953 SkIRect layerInputBounds = filter->filterBounds(
954 layerTargetBounds, layerMatrix, SkImageFilter::kReverse_MapDirection,
955 &layerTargetBounds);
956
957 // Map the required input into the root space, then make relative to the src device. This will
958 // be the conservative contents required to fill a layerInputBounds-sized surface with the
959 // backdrop content (transformed back into the layer space using fromRoot).
960 SkIRect backdropBounds = toRoot.mapRect(SkRect::Make(layerInputBounds)).roundOut();
961 backdropBounds.offset(-src->getOrigin().x(), -src->getOrigin().y());
962 if (!backdropBounds.intersect(srcDevRect)) {
963 return;
964 }
965
966 auto special = src->snapSpecial(backdropBounds);
967 if (!special) {
968 return;
969 }
970
971 SkColorType colorType = src->imageInfo().colorType();
972 if (colorType == kUnknown_SkColorType) {
973 colorType = kRGBA_8888_SkColorType;
974 }
975 SkColorSpace* colorSpace = src->imageInfo().colorSpace();
976
977 SkPaint p;
978 if (!toRoot.isIdentity()) {
979 // Drawing the temporary and final filtered image requires a higher filter quality if the
980 // 'toRoot' transformation is not identity, in order to minimize the impact on already
981 // rendered edges/content.
982 // TODO (michaelludwig) - Explore reducing this quality, identify visual tradeoffs
983 p.setFilterQuality(kHigh_SkFilterQuality);
984
985 // The snapped backdrop content needs to be transformed by fromRoot into the layer space,
986 // and stored in a temporary surface, which is then used as the input to the actual filter.
987 auto tmpSurface = special->makeSurface(colorType, colorSpace, layerInputBounds.size());
988 if (!tmpSurface) {
989 return;
990 }
991
992 auto tmpCanvas = tmpSurface->getCanvas();
993 tmpCanvas->clear(SK_ColorTRANSPARENT);
994 // Reading in reverse, this takes the backdrop bounds from src device space into the root
995 // space, then maps from root space into the layer space, then maps it so the input layer's
996 // top left corner is (0, 0). This transformation automatically accounts for any cropping
997 // performed on backdropBounds.
998 tmpCanvas->translate(-layerInputBounds.fLeft, -layerInputBounds.fTop);
999 tmpCanvas->concat(fromRoot);
1000 tmpCanvas->translate(src->getOrigin().x(), src->getOrigin().y());
1001
1002 tmpCanvas->drawImageRect(special->asImage(), special->subset(),
1003 SkRect::Make(backdropBounds), &p, kStrict_SrcRectConstraint);
1004 special = tmpSurface->makeImageSnapshot();
1005 } else {
1006 // Since there is no extra transform that was done, update the input bounds to reflect
1007 // cropping of the snapped backdrop image. In this case toRoot = I, so layerInputBounds
1008 // was equal to backdropBounds before it was made relative to the src device and cropped.
1009 // When we use the original snapped image directly, just map the update backdrop bounds
1010 // back into the shared layer space
1011 layerInputBounds = backdropBounds;
1012 layerInputBounds.offset(src->getOrigin().x(), src->getOrigin().y());
1013
1014 // Similar to the unfiltered case above, when toRoot is the identity, then the final
1015 // draw will be 1-1 so there is no need to increase filter quality.
1016 p.setFilterQuality(kNone_SkFilterQuality);
1017 }
1018
1019 // Now evaluate the filter on 'special', which contains the backdrop content mapped back into
1020 // layer space. This has to further offset everything so that filter evaluation thinks the
1021 // source image's top left corner is (0, 0).
1022 // TODO (michaelludwig) - Once image filters are robust to non-(0,0) image origins for inputs,
1023 // this can be simplified.
1024 layerTargetBounds.offset(-layerInputBounds.fLeft, -layerInputBounds.fTop);
1025 SkMatrix filterCTM = layerMatrix;
1026 filterCTM.postTranslate(-layerInputBounds.fLeft, -layerInputBounds.fTop);
1027 skif::Context ctx(filterCTM, layerTargetBounds, nullptr, colorType, colorSpace, special.get());
1028
1029 SkIPoint offset;
1030 special = as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset);
1031 if (special) {
1032 // Draw the filtered backdrop content into the dst device. We add layerInputBounds origin
1033 // to offset because the original value in 'offset' was relative to 'filterCTM'. 'filterCTM'
1034 // had subtracted the layerInputBounds origin, so adding that back makes 'offset' relative
1035 // to 'layerMatrix' (what we need it to be when drawing the image by 'toRoot').
1036 offset += layerInputBounds.topLeft();
1037
1038 // Manually setting the device's CTM requires accounting for the device's origin.
1039 // TODO (michaelludwig) - This could be simpler if the dst device had its origin configured
1040 // before filtering the backdrop device, and if SkAutoDeviceTransformRestore had a way to accept
1041 // a global CTM instead of a device CTM.
1042 SkMatrix dstCTM = toRoot;
1043 dstCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
1044 SkAutoDeviceTransformRestore adr(dst, dstCTM);
1045
1046 // And because devices don't have a special-image draw function that supports arbitrary
1047 // matrices, we are abusing the asImage() functionality here...
1048 SkRect specialSrc = SkRect::Make(special->subset());
1049 auto looseImage = special->asImage();
1050 dst->drawImageRect(
1051 looseImage.get(), &specialSrc,
1052 SkRect::MakeXYWH(offset.x(), offset.y(), special->width(), special->height()),
1053 p, kStrict_SrcRectConstraint);
1054 }
1055}
1056
1057static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
1058 SkColorType ct = prev.colorType();
1059 if (prev.bytesPerPixel() <= 4 &&
1060 prev.colorType() != kRGBA_8888_SkColorType &&
1061 prev.colorType() != kBGRA_8888_SkColorType) {
1062 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
1063 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
1064 ct = kN32_SkColorType;
1065 }
1066 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
1067}
1068
1069void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1070 TRACE_EVENT0("skia", TRACE_FUNC);
1071 const SkRect* bounds = rec.fBounds;
1072 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1073
1074 SkTCopyOnFirstWrite<SkPaint> paint(rec.fPaint);
1075 // saveLayer ignores mask filters, so force it to null
1076 if (paint.get() && paint->getMaskFilter()) {
1077 paint.writable()->setMaskFilter(nullptr);
1078 }
1079
1080 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
1081 // regardless of any hint-rect from the caller. skbug.com/8783
1082 if (rec.fBackdrop) {
1083 bounds = nullptr;
1084 }
1085
1086 SkImageFilter* imageFilter = paint.get() ? paint->getImageFilter() : nullptr;
1087 SkMatrix stashedMatrix = fMCRec->fMatrix;
1088 MCRec* modifiedRec = nullptr;
1089
1090 /*
1091 * Many ImageFilters (so far) do not (on their own) correctly handle matrices (CTM) that
1092 * contain rotation/skew/etc. We rely on applyCTM to create a new image filter DAG as needed to
1093 * accommodate this, but it requires update the CTM we use when drawing into the layer.
1094 *
1095 * 1. Stash off the current CTM
1096 * 2. Apply the CTM to imagefilter, which decomposes it into simple and complex transforms
1097 * if necessary.
1098 * 3. Wack the CTM to be the remaining scale matrix and use the modified imagefilter, which
1099 * is a MatrixImageFilter that contains the complex matrix.
1100 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1101 * 5. During restore, the MatrixImageFilter automatically applies complex stage to the output
1102 * of the original imagefilter, and draw that (via drawSprite)
1103 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1104 *
1105 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1106 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1107 */
1108 if (imageFilter) {
1109 SkMatrix modifiedCTM;
1110 sk_sp<SkImageFilter> modifiedFilter = as_IFB(imageFilter)->applyCTM(stashedMatrix,
1111 &modifiedCTM);
1112 if (as_IFB(modifiedFilter)->uniqueID() != as_IFB(imageFilter)->uniqueID()) {
1113 // The original filter couldn't support the CTM entirely
1114 SkASSERT(modifiedCTM.isScaleTranslate() || as_IFB(imageFilter)->canHandleComplexCTM());
1115 modifiedRec = fMCRec;
1116 this->internalSetMatrix(modifiedCTM);
1117 imageFilter = modifiedFilter.get();
1118 paint.writable()->setImageFilter(std::move(modifiedFilter));
1119 }
1120 // Else the filter didn't change, so modifiedCTM == stashedMatrix and there's nothing
1121 // left to do since the stack already has that as the CTM.
1122 }
1123
1124 // do this before we create the layer. We don't call the public save() since
1125 // that would invoke a possibly overridden virtual
1126 this->internalSave();
1127
1128 SkIRect ir;
1129 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
1130 if (modifiedRec) {
1131 // In this case there will be no layer in which to stash the matrix so we need to
1132 // revert the prior MCRec to its earlier state.
1133 modifiedRec->fMatrix = stashedMatrix;
1134 }
1135 return;
1136 }
1137
1138 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1139 // the clipRectBounds() call above?
1140 if (kNoLayer_SaveLayerStrategy == strategy) {
1141 return;
1142 }
1143
1144 SkPixelGeometry geo = fProps.pixelGeometry();
1145 if (paint) {
1146 // TODO: perhaps add a query to filters so we might preserve opaqueness...
1147 if (paint->getImageFilter() || paint->getColorFilter()) {
1148 geo = kUnknown_SkPixelGeometry;
1149 }
1150 }
1151
1152 SkBaseDevice* priorDevice = this->getTopDevice();
1153 if (nullptr == priorDevice) { // Do we still need this check???
1154 SkDebugf("Unable to find device for layer.");
1155 return;
1156 }
1157
1158 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
1159 if (rec.fSaveLayerFlags & kF16ColorType) {
1160 info = info.makeColorType(kRGBA_F16_SkColorType);
1161 }
1162
1163 sk_sp<SkBaseDevice> newDevice;
1164 {
1165 SkASSERT(info.alphaType() != kOpaque_SkAlphaType);
1166 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
1167 const bool trackCoverage =
1168 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
1169 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1170 trackCoverage,
1171 fAllocator.get());
1172 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1173 if (!newDevice) {
1174 return;
1175 }
1176 }
1177 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
1178
1179 // only have a "next" if this new layer doesn't affect the clip (rare)
1180 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
1181 fMCRec->fLayer = layer;
1182 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
1183
1184 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
1185 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
1186 fMCRec->fMatrix);
1187 }
1188
1189 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1190
1191 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1192 if (layer->fNext) {
1193 // need to punch a hole in the previous device, so we don't draw there, given that
1194 // the new top-layer will allow drawing to happen "below" it.
1195 SkRegion hole(ir);
1196 do {
1197 layer = layer->fNext;
1198 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1199 } while (layer->fNext);
1200 }
1201}
1202
1203int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1204 if (0xFF == alpha) {
1205 return this->saveLayer(bounds, nullptr);
1206 } else {
1207 SkPaint tmpPaint;
1208 tmpPaint.setAlpha(alpha);
1209 return this->saveLayer(bounds, &tmpPaint);
1210 }
1211}
1212
1213void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1214 SkBaseDevice* device = this->getTopDevice();
1215 if (nullptr == device) { // Do we still need this check???
1216 return;
1217 }
1218
1219 // Map the local bounds into the top device's coordinate space (this is not
1220 // necessarily the full global CTM transform).
1221 SkIRect devBounds;
1222 if (localBounds) {
1223 SkRect tmp;
1224 device->localToDevice().mapRect(&tmp, *localBounds);
1225 if (!devBounds.intersect(tmp.round(), device->devClipBounds())) {
1226 devBounds.setEmpty();
1227 }
1228 } else {
1229 devBounds = device->devClipBounds();
1230 }
1231 if (devBounds.isEmpty()) {
1232 return;
1233 }
1234
1235 // This is getting the special image from the current device, which is then drawn into (both by
1236 // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its
1237 // own device, we need to explicitly copy the back image contents so that its original content
1238 // is available when we splat it back later during restore.
1239 auto backImage = device->snapSpecial(devBounds, /* copy */ true);
1240 if (!backImage) {
1241 return;
1242 }
1243
1244 // we really need the save, so we can wack the fMCRec
1245 this->checkForDeferredSave();
1246
1247 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1248
1249 SkPaint paint;
1250 paint.setBlendMode(SkBlendMode::kClear);
1251 this->drawClippedToSaveBehind(paint);
1252}
1253
1254void SkCanvas::internalRestore() {
1255 SkASSERT(fMCStack.count() != 0);
1256
1257 // reserve our layer (if any)
1258 DeviceCM* layer = fMCRec->fLayer; // may be null
1259 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1260 fMCRec->fLayer = nullptr;
1261
1262 // move this out before we do the actual restore
1263 auto backImage = std::move(fMCRec->fBackImage);
1264
1265 while (!fMarkerStack.empty() && fMarkerStack.back().fMCRec == fMCRec) {
1266 fMarkerStack.pop_back();
1267 }
1268
1269 // now do the normal restore()
1270 fMCRec->~MCRec(); // balanced in save()
1271 fMCStack.pop_back();
1272 fMCRec = (MCRec*)fMCStack.back();
1273
1274 if (fMCRec) {
1275 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1276 }
1277
1278 if (backImage) {
1279 SkPaint paint;
1280 paint.setBlendMode(SkBlendMode::kDstOver);
1281 const int x = backImage->fLoc.x();
1282 const int y = backImage->fLoc.y();
1283 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1284 nullptr, SkMatrix::I());
1285 }
1286
1287 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1288 since if we're being recorded, we don't want to record this (the
1289 recorder will have already recorded the restore).
1290 */
1291 if (layer) {
1292 if (fMCRec) {
1293 layer->fDevice->setImmutable();
1294 // At this point, 'layer' has been removed from the device stack, so the devices that
1295 // internalDrawDevice sees are the destinations that 'layer' is drawn into.
1296 this->internalDrawDevice(layer->fDevice.get(), layer->fPaint.get(),
1297 layer->fClipImage.get(), layer->fClipMatrix);
1298 // restore what we smashed in internalSaveLayer
1299 this->internalSetMatrix(layer->fStashedMatrix);
1300 delete layer;
1301 } else {
1302 // we're at the root
1303 SkASSERT(layer == (void*)fDeviceCMStorage);
1304 layer->~DeviceCM();
1305 // no need to update fMCRec, 'cause we're killing the canvas
1306 }
1307 }
1308
1309 if (fMCRec) {
1310 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1311 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1312 }
1313}
1314
1315sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1316 if (nullptr == props) {
1317 props = &fProps;
1318 }
1319 return this->onNewSurface(info, *props);
1320}
1321
1322sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1323 SkBaseDevice* dev = this->getDevice();
1324 return dev ? dev->makeSurface(info, props) : nullptr;
1325}
1326
1327SkImageInfo SkCanvas::imageInfo() const {
1328 return this->onImageInfo();
1329}
1330
1331SkImageInfo SkCanvas::onImageInfo() const {
1332 SkBaseDevice* dev = this->getDevice();
1333 if (dev) {
1334 return dev->imageInfo();
1335 } else {
1336 return SkImageInfo::MakeUnknown(0, 0);
1337 }
1338}
1339
1340bool SkCanvas::getProps(SkSurfaceProps* props) const {
1341 return this->onGetProps(props);
1342}
1343
1344bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
1345 SkBaseDevice* dev = this->getDevice();
1346 if (dev) {
1347 if (props) {
1348 *props = fProps;
1349 }
1350 return true;
1351 } else {
1352 return false;
1353 }
1354}
1355
1356bool SkCanvas::peekPixels(SkPixmap* pmap) {
1357 return this->onPeekPixels(pmap);
1358}
1359
1360bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
1361 SkBaseDevice* dev = this->getDevice();
1362 return dev && dev->peekPixels(pmap);
1363}
1364
1365void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1366 SkPixmap pmap;
1367 if (!this->onAccessTopLayerPixels(&pmap)) {
1368 return nullptr;
1369 }
1370 if (info) {
1371 *info = pmap.info();
1372 }
1373 if (rowBytes) {
1374 *rowBytes = pmap.rowBytes();
1375 }
1376 if (origin) {
1377 // If the caller requested the origin, they presumably are expecting the returned pixels to
1378 // be axis-aligned with the root canvas. If the top level device isn't axis aligned, that's
1379 // not the case. Until we update accessTopLayerPixels() to accept a coord space matrix
1380 // instead of an origin, just don't expose the pixels in that case. Note that this means
1381 // that layers with complex coordinate spaces can still report their pixels if the caller
1382 // does not ask for the origin (e.g. just to dump its output to a file, etc).
1383 if (this->getTopDevice()->isPixelAlignedToGlobal()) {
1384 *origin = this->getTopDevice()->getOrigin();
1385 } else {
1386 return nullptr;
1387 }
1388 }
1389 return pmap.writable_addr();
1390}
1391
1392bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
1393 SkBaseDevice* dev = this->getTopDevice();
1394 return dev && dev->accessPixels(pmap);
1395}
1396
1397/////////////////////////////////////////////////////////////////////////////
1398
1399// In our current design/features, we should never have a layer (src) in a different colorspace
1400// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1401// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1402// colorspace.
1403static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1404 SkASSERT(src == dst);
1405}
1406
1407void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, const SkPaint* paint,
1408 SkImage* clipImage, const SkMatrix& clipMatrix) {
1409 SkPaint tmp;
1410 if (nullptr == paint) {
1411 paint = &tmp;
1412 }
1413
1414 DRAW_BEGIN_DRAWDEVICE(*paint)
1415
1416 while (iter.next()) {
1417 SkBaseDevice* dstDev = iter.fDevice;
1418 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1419 srcDev->imageInfo().colorSpace());
1420 paint = &draw.paint();
1421 SkImageFilter* filter = paint->getImageFilter();
1422 // TODO(michaelludwig) - Devices aren't created with complex coordinate systems yet,
1423 // so it should always be possible to use the relative origin. Once drawDevice() and
1424 // drawSpecial() take an SkMatrix, this can switch to getRelativeTransform() instead.
1425 SkIPoint pos = srcDev->getOrigin() - dstDev->getOrigin();
1426 if (filter || clipImage) {
1427 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1428 if (specialImage) {
1429 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1430 specialImage->getColorSpace());
1431 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1432 clipImage, clipMatrix);
1433 }
1434 } else {
1435 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
1436 }
1437 }
1438
1439 DRAW_END
1440}
1441
1442/////////////////////////////////////////////////////////////////////////////
1443
1444void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1445 if (dx || dy) {
1446 this->checkForDeferredSave();
1447 fMCRec->fMatrix.preTranslate(dx, dy);
1448
1449 // Translate shouldn't affect the is-scale-translateness of the matrix.
1450 // However, if either is non-finite, we might still complicate the matrix type,
1451 // so we still have to compute this.
1452 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1453
1454 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1455
1456 this->didTranslate(dx,dy);
1457 }
1458}
1459
1460void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1461 if (sx != 1 || sy != 1) {
1462 this->checkForDeferredSave();
1463 fMCRec->fMatrix.preScale(sx, sy);
1464
1465 // shouldn't need to do this (theoretically), as the state shouldn't have changed,
1466 // but pre-scaling by a non-finite does change it, so we have to recompute.
1467 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1468
1469 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1470
1471 this->didScale(sx, sy);
1472 }
1473}
1474
1475void SkCanvas::rotate(SkScalar degrees) {
1476 SkMatrix m;
1477 m.setRotate(degrees);
1478 this->concat(m);
1479}
1480
1481void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1482 SkMatrix m;
1483 m.setRotate(degrees, px, py);
1484 this->concat(m);
1485}
1486
1487void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1488 SkMatrix m;
1489 m.setSkew(sx, sy);
1490 this->concat(m);
1491}
1492
1493void SkCanvas::concat(const SkMatrix& matrix) {
1494 if (matrix.isIdentity()) {
1495 return;
1496 }
1497
1498 this->checkForDeferredSave();
1499 fMCRec->fMatrix.preConcat(matrix);
1500
1501 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1502
1503 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1504
1505 this->didConcat(matrix);
1506}
1507
1508void SkCanvas::internalConcat44(const SkM44& m) {
1509 this->checkForDeferredSave();
1510
1511 fMCRec->fMatrix.preConcat(m);
1512
1513 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1514
1515 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1516}
1517
1518void SkCanvas::concat(const SkM44& m) {
1519 this->internalConcat44(m);
1520 // notify subclasses
1521#ifdef SK_SUPPORT_LEGACY_DIDCONCAT44
1522 this->didConcat44(SkMatrixPriv::M44ColMajor(m));
1523#else
1524 this->didConcat44(m);
1525#endif
1526}
1527
1528void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
1529 fMCRec->fMatrix = matrix;
1530 fIsScaleTranslate = matrix.isScaleTranslate();
1531
1532 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1533}
1534
1535void SkCanvas::setMatrix(const SkMatrix& matrix) {
1536 this->checkForDeferredSave();
1537 this->internalSetMatrix(matrix);
1538 this->didSetMatrix(matrix);
1539}
1540
1541void SkCanvas::resetMatrix() {
1542 this->setMatrix(SkMatrix::I());
1543}
1544
1545void SkCanvas::markCTM(MarkerID id) {
1546 if (id == 0) return;
1547
1548 this->onMarkCTM(id);
1549
1550 SkM44 mx = this->getLocalToDevice();
1551
1552 // Look if we've already seen id in this save-frame.
1553 // If so, replace, else append
1554 for (int i = fMarkerStack.size() - 1; i >= 0; --i) {
1555 auto& m = fMarkerStack[i];
1556 if (m.fMCRec != fMCRec) { // we've gone past the current save-frame
1557 break; // fall out so we append
1558 }
1559 if (m.fID == id) { // in current frame, so replace
1560 m.fMatrix = mx;
1561 return;
1562 }
1563 }
1564 // if we get here, we should append a new marker
1565 fMarkerStack.push_back({fMCRec, mx, id});
1566}
1567
1568bool SkCanvas::findMarkedCTM(MarkerID id, SkM44* mx) const {
1569 // search from top to bottom, so we find the most recent id
1570 for (int i = fMarkerStack.size() - 1; i >= 0; --i) {
1571 if (fMarkerStack[i].fID == id) {
1572 if (mx) {
1573 *mx = fMarkerStack[i].fMatrix;
1574 }
1575 return true;
1576 }
1577 }
1578 return false;
1579}
1580
1581//////////////////////////////////////////////////////////////////////////////
1582
1583void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
1584 if (!rect.isFinite()) {
1585 return;
1586 }
1587 this->checkForDeferredSave();
1588 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1589 this->onClipRect(rect, op, edgeStyle);
1590}
1591
1592void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1593 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1594
1595 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
1596
1597 AutoValidateClip avc(this);
1598 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1599 isAA);
1600 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1601}
1602
1603void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1604 fClipRestrictionRect = rect;
1605 if (fClipRestrictionRect.isEmpty()) {
1606 // we notify the device, but we *dont* resolve deferred saves (since we're just
1607 // removing the restriction if the rect is empty. how I hate this api.
1608 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1609 } else {
1610 this->checkForDeferredSave();
1611 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1612 AutoValidateClip avc(this);
1613 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
1614 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1615 }
1616}
1617
1618void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
1619 this->checkForDeferredSave();
1620 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1621 if (rrect.isRect()) {
1622 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1623 } else {
1624 this->onClipRRect(rrect, op, edgeStyle);
1625 }
1626}
1627
1628void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1629 AutoValidateClip avc(this);
1630
1631 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1632
1633 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
1634
1635 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1636 isAA);
1637 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1638}
1639
1640void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
1641 this->checkForDeferredSave();
1642 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1643
1644 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1645 SkRect r;
1646 if (path.isRect(&r)) {
1647 this->onClipRect(r, op, edgeStyle);
1648 return;
1649 }
1650 SkRRect rrect;
1651 if (path.isOval(&r)) {
1652 rrect.setOval(r);
1653 this->onClipRRect(rrect, op, edgeStyle);
1654 return;
1655 }
1656 if (path.isRRect(&rrect)) {
1657 this->onClipRRect(rrect, op, edgeStyle);
1658 return;
1659 }
1660 }
1661
1662 this->onClipPath(path, op, edgeStyle);
1663}
1664
1665void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
1666 AutoValidateClip avc(this);
1667
1668 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1669
1670 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
1671
1672 const SkPath* rasterClipPath = &path;
1673 fMCRec->fRasterClip.opPath(*rasterClipPath, fMCRec->fMatrix, this->getTopLayerBounds(),
1674 (SkRegion::Op)op, isAA);
1675 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1676}
1677
1678void SkCanvas::clipShader(sk_sp<SkShader> sh, SkClipOp op) {
1679 if (sh) {
1680 if (sh->isOpaque()) {
1681 if (op == SkClipOp::kIntersect) {
1682 // we don't occlude anything, so skip this call
1683 } else {
1684 SkASSERT(op == SkClipOp::kDifference);
1685 // we occlude everything, so set the clip to empty
1686 this->clipRect({0,0,0,0});
1687 }
1688 } else {
1689 this->onClipShader(std::move(sh), op);
1690 }
1691 }
1692}
1693
1694void SkCanvas::onClipShader(sk_sp<SkShader> sh, SkClipOp op) {
1695 AutoValidateClip avc(this);
1696
1697 FOR_EACH_TOP_DEVICE(device->clipShader(sh, op));
1698
1699 // we don't know how to mutate our conservative bounds, so we don't
1700}
1701
1702void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
1703 this->checkForDeferredSave();
1704 this->onClipRegion(rgn, op);
1705}
1706
1707void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
1708 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
1709
1710 AutoValidateClip avc(this);
1711
1712 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
1713 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1714}
1715
1716#ifdef SK_DEBUG
1717void SkCanvas::validateClip() const {
1718 // construct clipRgn from the clipstack
1719 const SkBaseDevice* device = this->getDevice();
1720 if (!device) {
1721 SkASSERT(this->isClipEmpty());
1722 return;
1723 }
1724}
1725#endif
1726
1727bool SkCanvas::androidFramework_isClipAA() const {
1728 bool containsAA = false;
1729
1730 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1731
1732 return containsAA;
1733}
1734
1735class RgnAccumulator {
1736 SkRegion* fRgn;
1737public:
1738 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1739 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1740 SkIPoint origin = device->getOrigin();
1741 if (origin.x() | origin.y()) {
1742 rgn->translate(origin.x(), origin.y());
1743 }
1744 fRgn->op(*rgn, SkRegion::kUnion_Op);
1745 }
1746};
1747
1748void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1749 RgnAccumulator accum(rgn);
1750 SkRegion tmp;
1751
1752 rgn->setEmpty();
1753 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
1754}
1755
1756///////////////////////////////////////////////////////////////////////////////
1757
1758bool SkCanvas::isClipEmpty() const {
1759 return fMCRec->fRasterClip.isEmpty();
1760
1761 // TODO: should we only use the conservative answer in a recording canvas?
1762#if 0
1763 SkBaseDevice* dev = this->getTopDevice();
1764 // if no device we return true
1765 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
1766#endif
1767}
1768
1769bool SkCanvas::isClipRect() const {
1770 SkBaseDevice* dev = this->getTopDevice();
1771 // if no device we return false
1772 return dev && dev->onGetClipType() == SkBaseDevice::ClipType::kRect;
1773}
1774
1775static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1776#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1777 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1778 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1779 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1780 return 0xF != _mm_movemask_ps(mask);
1781#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1782 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1783 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1784 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1785 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1786#else
1787 SkRect devRectAsRect;
1788 SkRect devClipAsRect;
1789 devRect.store(&devRectAsRect.fLeft);
1790 devClip.store(&devClipAsRect.fLeft);
1791 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1792#endif
1793}
1794
1795// It's important for this function to not be inlined. Otherwise the compiler will share code
1796// between the fast path and the slow path, resulting in two slow paths.
1797static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1798 const SkMatrix& matrix) {
1799 SkRect deviceRect;
1800 matrix.mapRect(&deviceRect, src);
1801 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1802}
1803
1804bool SkCanvas::quickReject(const SkRect& src) const {
1805#ifdef SK_DEBUG
1806 // Verify that fDeviceClipBounds are set properly.
1807 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1808 if (fMCRec->fRasterClip.isEmpty()) {
1809 SkASSERT(fDeviceClipBounds.isEmpty());
1810 } else {
1811 SkASSERT(tmp == fDeviceClipBounds);
1812 }
1813
1814 // Verify that fIsScaleTranslate is set properly.
1815 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
1816#endif
1817
1818 if (!fIsScaleTranslate) {
1819 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1820 }
1821
1822 // We inline the implementation of mapScaleTranslate() for the fast path.
1823 float sx = fMCRec->fMatrix.getScaleX();
1824 float sy = fMCRec->fMatrix.getScaleY();
1825 float tx = fMCRec->fMatrix.getTranslateX();
1826 float ty = fMCRec->fMatrix.getTranslateY();
1827 Sk4f scale(sx, sy, sx, sy);
1828 Sk4f trans(tx, ty, tx, ty);
1829
1830 // Apply matrix.
1831 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1832
1833 // Make sure left < right, top < bottom.
1834 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1835 Sk4f min = Sk4f::Min(ltrb, rblt);
1836 Sk4f max = Sk4f::Max(ltrb, rblt);
1837 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1838 // ARM this sequence generates the fastest (a single instruction).
1839 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1840
1841 // Check if the device rect is NaN or outside the clip.
1842 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
1843}
1844
1845bool SkCanvas::quickReject(const SkPath& path) const {
1846 return path.isEmpty() || this->quickReject(path.getBounds());
1847}
1848
1849SkRect SkCanvas::getLocalClipBounds() const {
1850 SkIRect ibounds = this->getDeviceClipBounds();
1851 if (ibounds.isEmpty()) {
1852 return SkRect::MakeEmpty();
1853 }
1854
1855 SkMatrix inverse;
1856 // if we can't invert the CTM, we can't return local clip bounds
1857 if (!fMCRec->fMatrix.asM33().invert(&inverse)) {
1858 return SkRect::MakeEmpty();
1859 }
1860
1861 SkRect bounds;
1862 // adjust it outwards in case we are antialiasing
1863 const int margin = 1;
1864
1865 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
1866 inverse.mapRect(&bounds, r);
1867 return bounds;
1868}
1869
1870SkIRect SkCanvas::getDeviceClipBounds() const {
1871 return fMCRec->fRasterClip.getBounds();
1872}
1873
1874///////////////////////////////////////////////////////////////////////
1875
1876SkMatrix SkCanvas::getTotalMatrix() const {
1877 return fMCRec->fMatrix;
1878}
1879
1880SkM44 SkCanvas::getLocalToDevice() const {
1881 return fMCRec->fMatrix;
1882}
1883
1884GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
1885 SkBaseDevice* dev = this->getTopDevice();
1886 return dev ? dev->accessRenderTargetContext() : nullptr;
1887}
1888
1889GrContext* SkCanvas::getGrContext() {
1890 SkBaseDevice* device = this->getTopDevice();
1891 return device ? device->context() : nullptr;
1892}
1893
1894void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1895 const SkPaint& paint) {
1896 TRACE_EVENT0("skia", TRACE_FUNC);
1897 if (outer.isEmpty()) {
1898 return;
1899 }
1900 if (inner.isEmpty()) {
1901 this->drawRRect(outer, paint);
1902 return;
1903 }
1904
1905 // We don't have this method (yet), but technically this is what we should
1906 // be able to return ...
1907 // if (!outer.contains(inner))) {
1908 //
1909 // For now at least check for containment of bounds
1910 if (!outer.getBounds().contains(inner.getBounds())) {
1911 return;
1912 }
1913
1914 this->onDrawDRRect(outer, inner, paint);
1915}
1916
1917void SkCanvas::drawPaint(const SkPaint& paint) {
1918 TRACE_EVENT0("skia", TRACE_FUNC);
1919 this->onDrawPaint(paint);
1920}
1921
1922void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1923 TRACE_EVENT0("skia", TRACE_FUNC);
1924 // To avoid redundant logic in our culling code and various backends, we always sort rects
1925 // before passing them along.
1926 this->onDrawRect(r.makeSorted(), paint);
1927}
1928
1929void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1930 TRACE_EVENT0("skia", TRACE_FUNC);
1931 this->onDrawBehind(paint);
1932}
1933
1934void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1935 TRACE_EVENT0("skia", TRACE_FUNC);
1936 if (region.isEmpty()) {
1937 return;
1938 }
1939
1940 if (region.isRect()) {
1941 return this->drawIRect(region.getBounds(), paint);
1942 }
1943
1944 this->onDrawRegion(region, paint);
1945}
1946
1947void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1948 TRACE_EVENT0("skia", TRACE_FUNC);
1949 // To avoid redundant logic in our culling code and various backends, we always sort rects
1950 // before passing them along.
1951 this->onDrawOval(r.makeSorted(), paint);
1952}
1953
1954void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1955 TRACE_EVENT0("skia", TRACE_FUNC);
1956 this->onDrawRRect(rrect, paint);
1957}
1958
1959void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1960 TRACE_EVENT0("skia", TRACE_FUNC);
1961 this->onDrawPoints(mode, count, pts, paint);
1962}
1963
1964void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1965 const SkPaint& paint) {
1966 this->drawVertices(vertices.get(), mode, paint);
1967}
1968
1969void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1970 TRACE_EVENT0("skia", TRACE_FUNC);
1971 RETURN_ON_NULL(vertices);
1972
1973 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1974 SkASSERT(vertices->priv().mode() != SkVertices::kTriangleFan_VertexMode);
1975
1976 // If the vertices contain custom attributes, ensure they line up with the paint's shader
1977 const SkRuntimeEffect* effect =
1978 paint.getShader() ? as_SB(paint.getShader())->asRuntimeEffect() : nullptr;
1979 if ((size_t)vertices->priv().attributeCount() != (effect ? effect->varyings().count() : 0)) {
1980 return;
1981 }
1982 if (effect) {
1983 int attrIndex = 0;
1984 for (const auto& v : effect->varyings()) {
1985 if (vertices->priv().attributes()[attrIndex++].channelCount() != v.fWidth) {
1986 return;
1987 }
1988 }
1989 }
1990
1991 this->onDrawVerticesObject(vertices, mode, paint);
1992}
1993
1994void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1995 TRACE_EVENT0("skia", TRACE_FUNC);
1996 this->onDrawPath(path, paint);
1997}
1998
1999void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
2000 TRACE_EVENT0("skia", TRACE_FUNC);
2001 RETURN_ON_NULL(image);
2002 this->onDrawImage(image, x, y, paint);
2003}
2004
2005// Returns true if the rect can be "filled" : non-empty and finite
2006static bool fillable(const SkRect& r) {
2007 SkScalar w = r.width();
2008 SkScalar h = r.height();
2009 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
2010}
2011
2012void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
2013 const SkPaint* paint, SrcRectConstraint constraint) {
2014 TRACE_EVENT0("skia", TRACE_FUNC);
2015 RETURN_ON_NULL(image);
2016 if (!fillable(dst) || !fillable(src)) {
2017 return;
2018 }
2019 this->onDrawImageRect(image, &src, dst, paint, constraint);
2020}
2021
2022void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
2023 const SkPaint* paint, SrcRectConstraint constraint) {
2024 RETURN_ON_NULL(image);
2025 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
2026}
2027
2028void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
2029 RETURN_ON_NULL(image);
2030 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
2031 kFast_SrcRectConstraint);
2032}
2033
2034namespace {
2035class LatticePaint : SkNoncopyable {
2036public:
2037 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
2038 if (!origPaint) {
2039 return;
2040 }
2041 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
2042 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
2043 }
2044 if (origPaint->getMaskFilter()) {
2045 fPaint.writable()->setMaskFilter(nullptr);
2046 }
2047 if (origPaint->isAntiAlias()) {
2048 fPaint.writable()->setAntiAlias(false);
2049 }
2050 }
2051
2052 const SkPaint* get() const {
2053 return fPaint;
2054 }
2055
2056private:
2057 SkTCopyOnFirstWrite<SkPaint> fPaint;
2058};
2059} // namespace
2060
2061void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2062 const SkPaint* paint) {
2063 TRACE_EVENT0("skia", TRACE_FUNC);
2064 RETURN_ON_NULL(image);
2065 if (dst.isEmpty()) {
2066 return;
2067 }
2068 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2069 LatticePaint latticePaint(paint);
2070 this->onDrawImageNine(image, center, dst, latticePaint.get());
2071 } else {
2072 this->drawImageRect(image, dst, paint);
2073 }
2074}
2075
2076void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2077 const SkPaint* paint) {
2078 TRACE_EVENT0("skia", TRACE_FUNC);
2079 RETURN_ON_NULL(image);
2080 if (dst.isEmpty()) {
2081 return;
2082 }
2083
2084 SkIRect bounds;
2085 Lattice latticePlusBounds = lattice;
2086 if (!latticePlusBounds.fBounds) {
2087 bounds = SkIRect::MakeWH(image->width(), image->height());
2088 latticePlusBounds.fBounds = &bounds;
2089 }
2090
2091 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
2092 LatticePaint latticePaint(paint);
2093 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
2094 } else {
2095 this->drawImageRect(image, dst, paint);
2096 }
2097}
2098
2099static sk_sp<SkImage> bitmap_as_image(const SkBitmap& bitmap) {
2100 if (bitmap.drawsNothing()) {
2101 return nullptr;
2102 }
2103 return SkImage::MakeFromBitmap(bitmap);
2104}
2105
2106void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
2107 this->drawImage(bitmap_as_image(bitmap), dx, dy, paint);
2108}
2109
2110void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
2111 const SkPaint* paint, SrcRectConstraint constraint) {
2112 this->drawImageRect(bitmap_as_image(bitmap), src, dst, paint, constraint);
2113}
2114
2115void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2116 const SkPaint* paint, SrcRectConstraint constraint) {
2117 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
2118}
2119
2120void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2121 SrcRectConstraint constraint) {
2122 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2123 constraint);
2124}
2125
2126void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2127 const SkColor colors[], int count, SkBlendMode mode,
2128 const SkRect* cull, const SkPaint* paint) {
2129 TRACE_EVENT0("skia", TRACE_FUNC);
2130 RETURN_ON_NULL(atlas);
2131 if (count <= 0) {
2132 return;
2133 }
2134 SkASSERT(atlas);
2135 SkASSERT(tex);
2136 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2137}
2138
2139void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2140 TRACE_EVENT0("skia", TRACE_FUNC);
2141 if (key) {
2142 this->onDrawAnnotation(rect, key, value);
2143 }
2144}
2145
2146void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2147 const SkPaint* paint, SrcRectConstraint constraint) {
2148 if (src) {
2149 this->drawImageRect(image, *src, dst, paint, constraint);
2150 } else {
2151 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2152 dst, paint, constraint);
2153 }
2154}
2155
2156void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
2157 TRACE_EVENT0("skia", TRACE_FUNC);
2158 this->onDrawShadowRec(path, rec);
2159}
2160
2161void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
2162 SkPaint paint;
2163 const SkRect& pathBounds = path.getBounds();
2164
2165 DRAW_BEGIN(paint, &pathBounds)
2166 while (iter.next()) {
2167 iter.fDevice->drawShadow(path, rec);
2168 }
2169 DRAW_END
2170}
2171
2172void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2173 QuadAAFlags aaFlags, const SkColor4f& color,
2174 SkBlendMode mode) {
2175 TRACE_EVENT0("skia", TRACE_FUNC);
2176 // Make sure the rect is sorted before passing it along
2177 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2178}
2179
2180void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2181 const SkPoint dstClips[],
2182 const SkMatrix preViewMatrices[],
2183 const SkPaint* paint,
2184 SrcRectConstraint constraint) {
2185 TRACE_EVENT0("skia", TRACE_FUNC);
2186 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2187}
2188
2189//////////////////////////////////////////////////////////////////////////////
2190// These are the virtual drawing methods
2191//////////////////////////////////////////////////////////////////////////////
2192
2193void SkCanvas::onDiscard() {
2194 if (fSurfaceBase) {
2195 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2196 }
2197}
2198
2199void SkCanvas::onDrawPaint(const SkPaint& paint) {
2200 this->internalDrawPaint(paint);
2201}
2202
2203void SkCanvas::internalDrawPaint(const SkPaint& paint) {
2204 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
2205
2206 while (iter.next()) {
2207 iter.fDevice->drawPaint(draw.paint());
2208 }
2209
2210 DRAW_END
2211}
2212
2213void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2214 const SkPaint& paint) {
2215 if ((long)count <= 0) {
2216 return;
2217 }
2218
2219 SkRect r;
2220 const SkRect* bounds = nullptr;
2221 if (paint.canComputeFastBounds()) {
2222 // special-case 2 points (common for drawing a single line)
2223 if (2 == count) {
2224 r.set(pts[0], pts[1]);
2225 } else {
2226 r.setBounds(pts, SkToInt(count));
2227 }
2228 if (!r.isFinite()) {
2229 return;
2230 }
2231 SkRect storage;
2232 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2233 return;
2234 }
2235 bounds = &r;
2236 }
2237
2238 SkASSERT(pts != nullptr);
2239
2240 DRAW_BEGIN(paint, bounds)
2241
2242 while (iter.next()) {
2243 iter.fDevice->drawPoints(mode, count, pts, draw.paint());
2244 }
2245
2246 DRAW_END
2247}
2248
2249static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2250 return paint.getImageFilter() != nullptr;
2251}
2252
2253void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
2254 SkASSERT(r.isSorted());
2255 if (paint.canComputeFastBounds()) {
2256 SkRect storage;
2257 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2258 return;
2259 }
2260 }
2261
2262 if (needs_autodrawlooper(this, paint)) {
2263 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
2264
2265 while (iter.next()) {
2266 iter.fDevice->drawRect(r, draw.paint());
2267 }
2268
2269 DRAW_END
2270 } else if (!paint.nothingToDraw()) {
2271 this->predrawNotify(&r, &paint, false);
2272 SkDrawIter iter(this);
2273 while (iter.next()) {
2274 iter.fDevice->drawRect(r, paint);
2275 }
2276 }
2277}
2278
2279void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2280 SkRect regionRect = SkRect::Make(region.getBounds());
2281 if (paint.canComputeFastBounds()) {
2282 SkRect storage;
2283 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2284 return;
2285 }
2286 }
2287
2288 DRAW_BEGIN(paint, &regionRect)
2289
2290 while (iter.next()) {
2291 iter.fDevice->drawRegion(region, draw.paint());
2292 }
2293
2294 DRAW_END
2295}
2296
2297void SkCanvas::onDrawBehind(const SkPaint& paint) {
2298 SkIRect bounds;
2299 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2300 for (;;) {
2301 const MCRec* rec = (const MCRec*)iter.prev();
2302 if (!rec) {
2303 return; // no backimages, so nothing to draw
2304 }
2305 if (rec->fBackImage) {
2306 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2307 rec->fBackImage->fImage->width(),
2308 rec->fBackImage->fImage->height());
2309 break;
2310 }
2311 }
2312
2313 DRAW_BEGIN(paint, nullptr)
2314
2315 while (iter.next()) {
2316 SkBaseDevice* dev = iter.fDevice;
2317
2318 dev->save();
2319 // We use clipRegion because it is already defined to operate in dev-space
2320 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2321 // but we don't want that, so we undo that before calling in.
2322 SkRegion rgn(bounds.makeOffset(dev->getOrigin()));
2323 dev->clipRegion(rgn, SkClipOp::kIntersect);
2324 dev->drawPaint(draw.paint());
2325 dev->restore(fMCRec->fMatrix);
2326 }
2327
2328 DRAW_END
2329}
2330
2331void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
2332 SkASSERT(oval.isSorted());
2333 if (paint.canComputeFastBounds()) {
2334 SkRect storage;
2335 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2336 return;
2337 }
2338 }
2339
2340 DRAW_BEGIN(paint, &oval)
2341
2342 while (iter.next()) {
2343 iter.fDevice->drawOval(oval, draw.paint());
2344 }
2345
2346 DRAW_END
2347}
2348
2349void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2350 SkScalar sweepAngle, bool useCenter,
2351 const SkPaint& paint) {
2352 SkASSERT(oval.isSorted());
2353 if (paint.canComputeFastBounds()) {
2354 SkRect storage;
2355 // Note we're using the entire oval as the bounds.
2356 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2357 return;
2358 }
2359 }
2360
2361 DRAW_BEGIN(paint, &oval)
2362
2363 while (iter.next()) {
2364 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, draw.paint());
2365 }
2366
2367 DRAW_END
2368}
2369
2370void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
2371 if (paint.canComputeFastBounds()) {
2372 SkRect storage;
2373 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2374 return;
2375 }
2376 }
2377
2378 if (rrect.isRect()) {
2379 // call the non-virtual version
2380 this->SkCanvas::drawRect(rrect.getBounds(), paint);
2381 return;
2382 } else if (rrect.isOval()) {
2383 // call the non-virtual version
2384 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2385 return;
2386 }
2387
2388 DRAW_BEGIN(paint, &rrect.getBounds())
2389
2390 while (iter.next()) {
2391 iter.fDevice->drawRRect(rrect, draw.paint());
2392 }
2393
2394 DRAW_END
2395}
2396
2397void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
2398 if (paint.canComputeFastBounds()) {
2399 SkRect storage;
2400 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2401 return;
2402 }
2403 }
2404
2405 DRAW_BEGIN(paint, &outer.getBounds())
2406
2407 while (iter.next()) {
2408 iter.fDevice->drawDRRect(outer, inner, draw.paint());
2409 }
2410
2411 DRAW_END
2412}
2413
2414void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
2415 if (!path.isFinite()) {
2416 return;
2417 }
2418
2419 const SkRect& pathBounds = path.getBounds();
2420 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
2421 SkRect storage;
2422 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2423 return;
2424 }
2425 }
2426
2427 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
2428 if (path.isInverseFillType()) {
2429 this->internalDrawPaint(paint);
2430 return;
2431 }
2432 }
2433
2434 DRAW_BEGIN(paint, &pathBounds)
2435
2436 while (iter.next()) {
2437 iter.fDevice->drawPath(path, draw.paint());
2438 }
2439
2440 DRAW_END
2441}
2442
2443bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
2444 if (!paint.getImageFilter()) {
2445 return false;
2446 }
2447
2448 const SkMatrix& ctm = this->getTotalMatrix();
2449 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
2450 return false;
2451 }
2452
2453 // The other paint effects need to be applied before the image filter, but the sprite draw
2454 // applies the filter explicitly first.
2455 if (paint.getAlphaf() < 1.f || paint.getColorFilter() || paint.getMaskFilter()) {
2456 return false;
2457 }
2458 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2459 // Once we can filter and the filter will return a result larger than itself, we should be
2460 // able to remove this constraint.
2461 // skbug.com/4526
2462 //
2463 SkPoint pt;
2464 ctm.mapXY(x, y, &pt);
2465 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2466 return ir.contains(fMCRec->fRasterClip.getBounds());
2467}
2468
2469// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2470// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2471// null.
2472static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2473 if (paintParam) {
2474 *real = *paintParam;
2475 real->setStyle(SkPaint::kFill_Style);
2476 real->setPathEffect(nullptr);
2477 paintParam = real;
2478 }
2479 return paintParam;
2480}
2481
2482void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
2483 SkPaint realPaint;
2484 paint = init_image_paint(&realPaint, paint);
2485
2486 SkRect bounds = SkRect::MakeXYWH(x, y,
2487 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
2488 if (nullptr == paint || paint->canComputeFastBounds()) {
2489 SkRect tmp = bounds;
2490 if (paint) {
2491 paint->computeFastBounds(tmp, &tmp);
2492 }
2493 if (this->quickReject(tmp)) {
2494 return;
2495 }
2496 }
2497 // At this point we need a real paint object. If the caller passed null, then we should
2498 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2499 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2500 paint = &realPaint;
2501
2502 sk_sp<SkSpecialImage> special;
2503 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2504 *paint);
2505 if (drawAsSprite && paint->getImageFilter()) {
2506 special = this->getDevice()->makeSpecial(image);
2507 if (!special) {
2508 drawAsSprite = false;
2509 }
2510 }
2511
2512 DRAW_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2513
2514 while (iter.next()) {
2515 const SkPaint& pnt = draw.paint();
2516 if (special) {
2517 SkPoint pt;
2518 iter.fDevice->localToDevice().mapXY(x, y, &pt);
2519 iter.fDevice->drawSpecial(special.get(),
2520 SkScalarRoundToInt(pt.fX),
2521 SkScalarRoundToInt(pt.fY), pnt,
2522 nullptr, SkMatrix::I());
2523 } else {
2524 iter.fDevice->drawImageRect(
2525 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2526 kStrict_SrcRectConstraint);
2527 }
2528 }
2529
2530 DRAW_END
2531}
2532
2533void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2534 const SkPaint* paint, SrcRectConstraint constraint) {
2535 SkPaint realPaint;
2536 paint = init_image_paint(&realPaint, paint);
2537
2538 if (nullptr == paint || paint->canComputeFastBounds()) {
2539 SkRect storage = dst;
2540 if (paint) {
2541 paint->computeFastBounds(dst, &storage);
2542 }
2543 if (this->quickReject(storage)) {
2544 return;
2545 }
2546 }
2547 paint = &realPaint;
2548
2549 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
2550
2551 while (iter.next()) {
2552 iter.fDevice->drawImageRect(image, src, dst, draw.paint(), constraint);
2553 }
2554
2555 DRAW_END
2556}
2557
2558void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2559 const SkPaint* paint) {
2560 SkPaint realPaint;
2561 paint = init_image_paint(&realPaint, paint);
2562
2563 if (nullptr == paint || paint->canComputeFastBounds()) {
2564 SkRect storage;
2565 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2566 return;
2567 }
2568 }
2569 paint = &realPaint;
2570
2571 DRAW_BEGIN(*paint, &dst)
2572
2573 while (iter.next()) {
2574 iter.fDevice->drawImageNine(image, center, dst, draw.paint());
2575 }
2576
2577 DRAW_END
2578}
2579
2580void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2581 const SkPaint* paint) {
2582 SkPaint realPaint;
2583 paint = init_image_paint(&realPaint, paint);
2584
2585 if (nullptr == paint || paint->canComputeFastBounds()) {
2586 SkRect storage;
2587 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2588 return;
2589 }
2590 }
2591 paint = &realPaint;
2592
2593 DRAW_BEGIN(*paint, &dst)
2594
2595 while (iter.next()) {
2596 iter.fDevice->drawImageLattice(image, lattice, dst, draw.paint());
2597 }
2598
2599 DRAW_END
2600}
2601
2602void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2603 const SkPaint& paint) {
2604 SkRect storage;
2605 const SkRect* bounds = nullptr;
2606 if (paint.canComputeFastBounds()) {
2607 storage = blob->bounds().makeOffset(x, y);
2608 SkRect tmp;
2609 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2610 return;
2611 }
2612 bounds = &storage;
2613 }
2614
2615 // We cannot filter in the looper as we normally do, because the paint is
2616 // incomplete at this point (text-related attributes are embedded within blob run paints).
2617 DRAW_BEGIN(paint, bounds)
2618
2619 while (iter.next()) {
2620 fScratchGlyphRunBuilder->drawTextBlob(draw.paint(), *blob, {x, y}, iter.fDevice);
2621 }
2622
2623 DRAW_END
2624}
2625
2626// These call the (virtual) onDraw... method
2627void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
2628 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2629 TRACE_EVENT0("skia", TRACE_FUNC);
2630 if (byteLength) {
2631 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
2632 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
2633 }
2634}
2635
2636void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2637 const SkPaint& paint) {
2638 TRACE_EVENT0("skia", TRACE_FUNC);
2639 RETURN_ON_NULL(blob);
2640 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
2641 this->onDrawTextBlob(blob, x, y, paint);
2642}
2643
2644void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2645 const SkPaint& paint) {
2646 DRAW_BEGIN(paint, nullptr)
2647
2648 while (iter.next()) {
2649 // In the common case of one iteration we could std::move vertices here.
2650 iter.fDevice->drawVertices(vertices, bmode, draw.paint());
2651 }
2652
2653 DRAW_END
2654}
2655
2656void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2657 const SkPoint texCoords[4], SkBlendMode bmode,
2658 const SkPaint& paint) {
2659 TRACE_EVENT0("skia", TRACE_FUNC);
2660 if (nullptr == cubics) {
2661 return;
2662 }
2663
2664 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
2665}
2666
2667void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2668 const SkPoint texCoords[4], SkBlendMode bmode,
2669 const SkPaint& paint) {
2670 // Since a patch is always within the convex hull of the control points, we discard it when its
2671 // bounding rectangle is completely outside the current clip.
2672 SkRect bounds;
2673 bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts);
2674 if (this->quickReject(bounds)) {
2675 return;
2676 }
2677
2678 DRAW_BEGIN(paint, nullptr)
2679
2680 while (iter.next()) {
2681 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
2682 }
2683
2684 DRAW_END
2685}
2686
2687void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2688#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2689 TRACE_EVENT0("skia", TRACE_FUNC);
2690#endif
2691 RETURN_ON_NULL(dr);
2692 if (x || y) {
2693 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2694 this->onDrawDrawable(dr, &matrix);
2695 } else {
2696 this->onDrawDrawable(dr, nullptr);
2697 }
2698}
2699
2700void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2701#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2702 TRACE_EVENT0("skia", TRACE_FUNC);
2703#endif
2704 RETURN_ON_NULL(dr);
2705 if (matrix && matrix->isIdentity()) {
2706 matrix = nullptr;
2707 }
2708 this->onDrawDrawable(dr, matrix);
2709}
2710
2711void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2712 // drawable bounds are no longer reliable (e.g. android displaylist)
2713 // so don't use them for quick-reject
2714 this->getDevice()->drawDrawable(dr, matrix, this);
2715}
2716
2717void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2718 const SkColor colors[], int count, SkBlendMode bmode,
2719 const SkRect* cull, const SkPaint* paint) {
2720 if (cull && this->quickReject(*cull)) {
2721 return;
2722 }
2723
2724 SkPaint pnt;
2725 if (paint) {
2726 pnt = *paint;
2727 }
2728
2729 DRAW_BEGIN(pnt, nullptr)
2730 while (iter.next()) {
2731 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
2732 }
2733 DRAW_END
2734}
2735
2736void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2737 SkASSERT(key);
2738
2739 SkPaint paint;
2740 DRAW_BEGIN(paint, nullptr)
2741 while (iter.next()) {
2742 iter.fDevice->drawAnnotation(rect, key, value);
2743 }
2744 DRAW_END
2745}
2746
2747void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2748 const SkColor4f& color, SkBlendMode mode) {
2749 SkASSERT(r.isSorted());
2750
2751 // If this used a paint, it would be a filled color with blend mode, which does not
2752 // need to use an autodraw loop, so use SkDrawIter directly.
2753 if (this->quickReject(r)) {
2754 return;
2755 }
2756
2757 this->predrawNotify(&r, nullptr, false);
2758 SkDrawIter iter(this);
2759 while(iter.next()) {
2760 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2761 }
2762}
2763
2764void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2765 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2766 const SkPaint* paint, SrcRectConstraint constraint) {
2767 if (count <= 0) {
2768 // Nothing to draw
2769 return;
2770 }
2771
2772 SkPaint realPaint;
2773 init_image_paint(&realPaint, paint);
2774
2775 // We could calculate the set's dstRect union to always check quickReject(), but we can't reject
2776 // individual entries and Chromium's occlusion culling already makes it likely that at least one
2777 // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1),
2778 // or we need it for the autolooper (since it greatly improves image filter perf).
2779 bool needsAutoLooper = needs_autodrawlooper(this, realPaint);
2780 bool setBoundsValid = count == 1 || needsAutoLooper;
2781 SkRect setBounds = imageSet[0].fDstRect;
2782 if (imageSet[0].fMatrixIndex >= 0) {
2783 // Account for the per-entry transform that is applied prior to the CTM when drawing
2784 preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds);
2785 }
2786 if (needsAutoLooper) {
2787 for (int i = 1; i < count; ++i) {
2788 SkRect entryBounds = imageSet[i].fDstRect;
2789 if (imageSet[i].fMatrixIndex >= 0) {
2790 preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds);
2791 }
2792 setBounds.joinPossiblyEmptyRect(entryBounds);
2793 }
2794 }
2795
2796 // If we happen to have the draw bounds, though, might as well check quickReject().
2797 if (setBoundsValid && realPaint.canComputeFastBounds()) {
2798 SkRect tmp;
2799 if (this->quickReject(realPaint.computeFastBounds(setBounds, &tmp))) {
2800 return;
2801 }
2802 }
2803
2804 if (needsAutoLooper) {
2805 SkASSERT(setBoundsValid);
2806 DRAW_BEGIN(realPaint, &setBounds)
2807 while (iter.next()) {
2808 iter.fDevice->drawEdgeAAImageSet(
2809 imageSet, count, dstClips, preViewMatrices, draw.paint(), constraint);
2810 }
2811 DRAW_END
2812 } else {
2813 this->predrawNotify();
2814 SkDrawIter iter(this);
2815 while(iter.next()) {
2816 iter.fDevice->drawEdgeAAImageSet(
2817 imageSet, count, dstClips, preViewMatrices, realPaint, constraint);
2818 }
2819 }
2820}
2821
2822//////////////////////////////////////////////////////////////////////////////
2823// These methods are NOT virtual, and therefore must call back into virtual
2824// methods, rather than actually drawing themselves.
2825//////////////////////////////////////////////////////////////////////////////
2826
2827void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
2828 SkPaint paint;
2829 paint.setColor(c);
2830 paint.setBlendMode(mode);
2831 this->drawPaint(paint);
2832}
2833
2834void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2835 const SkPoint pt = { x, y };
2836 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2837}
2838
2839void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
2840 SkPoint pts[2];
2841 pts[0].set(x0, y0);
2842 pts[1].set(x1, y1);
2843 this->drawPoints(kLines_PointMode, 2, pts, paint);
2844}
2845
2846void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
2847 if (radius < 0) {
2848 radius = 0;
2849 }
2850
2851 SkRect r;
2852 r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
2853 this->drawOval(r, paint);
2854}
2855
2856void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2857 const SkPaint& paint) {
2858 if (rx > 0 && ry > 0) {
2859 SkRRect rrect;
2860 rrect.setRectXY(r, rx, ry);
2861 this->drawRRect(rrect, paint);
2862 } else {
2863 this->drawRect(r, paint);
2864 }
2865}
2866
2867void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2868 SkScalar sweepAngle, bool useCenter,
2869 const SkPaint& paint) {
2870 TRACE_EVENT0("skia", TRACE_FUNC);
2871 if (oval.isEmpty() || !sweepAngle) {
2872 return;
2873 }
2874 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
2875}
2876
2877///////////////////////////////////////////////////////////////////////////////
2878#ifdef SK_DISABLE_SKPICTURE
2879void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
2880
2881
2882void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2883 const SkPaint* paint) {}
2884#else
2885/**
2886 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2887 * against the playback cost of recursing into the subpicture to get at its actual ops.
2888 *
2889 * For now we pick a conservatively small value, though measurement (and other heuristics like
2890 * the type of ops contained) may justify changing this value.
2891 */
2892#define kMaxPictureOpsToUnrollInsteadOfRef 1
2893
2894void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2895 TRACE_EVENT0("skia", TRACE_FUNC);
2896 RETURN_ON_NULL(picture);
2897
2898 if (matrix && matrix->isIdentity()) {
2899 matrix = nullptr;
2900 }
2901 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2902 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2903 picture->playback(this);
2904 } else {
2905 this->onDrawPicture(picture, matrix, paint);
2906 }
2907}
2908
2909void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2910 const SkPaint* paint) {
2911 if (!paint || paint->canComputeFastBounds()) {
2912 SkRect bounds = picture->cullRect();
2913 if (paint) {
2914 paint->computeFastBounds(bounds, &bounds);
2915 }
2916 if (matrix) {
2917 matrix->mapRect(&bounds);
2918 }
2919 if (this->quickReject(bounds)) {
2920 return;
2921 }
2922 }
2923
2924 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2925 picture->playback(this);
2926}
2927#endif
2928
2929///////////////////////////////////////////////////////////////////////////////
2930///////////////////////////////////////////////////////////////////////////////
2931
2932SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
2933 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
2934
2935 SkASSERT(canvas);
2936
2937 fImpl = new (fStorage) SkDrawIter(canvas);
2938 // This advances the base iterator to the first device and caches its origin,
2939 // correctly handling the case where there are no devices.
2940 this->next();
2941}
2942
2943SkCanvas::LayerIter::~LayerIter() {
2944 fImpl->~SkDrawIter();
2945}
2946
2947void SkCanvas::LayerIter::next() {
2948 fDone = !fImpl->next();
2949 if (!fDone) {
2950 // Cache the device origin. LayerIter is only used in Android, which doesn't use image
2951 // filters, so its devices will always be able to report the origin exactly.
2952 fDeviceOrigin = fImpl->fDevice->getOrigin();
2953 }
2954}
2955
2956SkBaseDevice* SkCanvas::LayerIter::device() const {
2957 return fImpl->fDevice;
2958}
2959
2960const SkMatrix& SkCanvas::LayerIter::matrix() const {
2961 return fImpl->fDevice->localToDevice();
2962}
2963
2964const SkPaint& SkCanvas::LayerIter::paint() const {
2965 const SkPaint* paint = fImpl->getPaint();
2966 if (nullptr == paint) {
2967 paint = &fDefaultPaint;
2968 }
2969 return *paint;
2970}
2971
2972SkIRect SkCanvas::LayerIter::clipBounds() const {
2973 return fImpl->fDevice->getGlobalBounds();
2974}
2975
2976int SkCanvas::LayerIter::x() const { return fDeviceOrigin.fX; }
2977int SkCanvas::LayerIter::y() const { return fDeviceOrigin.fY; }
2978
2979///////////////////////////////////////////////////////////////////////////////
2980
2981SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2982SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2983SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2984SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2985
2986SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2987 const SkRect& dstRect, int matrixIndex, float alpha,
2988 unsigned aaFlags, bool hasClip)
2989 : fImage(std::move(image))
2990 , fSrcRect(srcRect)
2991 , fDstRect(dstRect)
2992 , fMatrixIndex(matrixIndex)
2993 , fAlpha(alpha)
2994 , fAAFlags(aaFlags)
2995 , fHasClip(hasClip) {}
2996
2997SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2998 const SkRect& dstRect, float alpha, unsigned aaFlags)
2999 : fImage(std::move(image))
3000 , fSrcRect(srcRect)
3001 , fDstRect(dstRect)
3002 , fAlpha(alpha)
3003 , fAAFlags(aaFlags) {}
3004
3005///////////////////////////////////////////////////////////////////////////////
3006
3007std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3008 size_t rowBytes, const SkSurfaceProps* props) {
3009 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
3010 return nullptr;
3011 }
3012
3013 SkBitmap bitmap;
3014 if (!bitmap.installPixels(info, pixels, rowBytes)) {
3015 return nullptr;
3016 }
3017
3018 return props ?
3019 std::make_unique<SkCanvas>(bitmap, *props) :
3020 std::make_unique<SkCanvas>(bitmap);
3021}
3022
3023///////////////////////////////////////////////////////////////////////////////
3024
3025SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3026 : INHERITED(SkIRect::MakeWH(width, height)) {}
3027
3028SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3029 : INHERITED(bounds) {}
3030
3031SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
3032 : INHERITED(device) {}
3033
3034SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3035 (void)this->INHERITED::getSaveLayerStrategy(rec);
3036 return kNoLayer_SaveLayerStrategy;
3037}
3038
3039bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
3040 return false;
3041}
3042
3043///////////////////////////////////////////////////////////////////////////////
3044
3045static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3046static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3047static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3048static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3049static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3050static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
3051
3052///////////////////////////////////////////////////////////////////////////////////////////////////
3053
3054SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3055 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3056 const auto& dev = fMCRec->fTopLayer->fDevice;
3057 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3058 SkIRect clip = dev->devClipBounds();
3059 if (!clip.intersect({0, 0, dev->width(), dev->height()})) {
3060 clip.setEmpty();
3061 }
3062
3063 fAllocator->updateHandle(handle, dev->localToDevice(), clip);
3064 return handle;
3065 }
3066 return nullptr;
3067}
3068
3069static bool install(SkBitmap* bm, const SkImageInfo& info,
3070 const SkRasterHandleAllocator::Rec& rec) {
3071 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
3072}
3073
3074SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3075 SkBitmap* bm) {
3076 SkRasterHandleAllocator::Rec rec;
3077 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3078 return nullptr;
3079 }
3080 return rec.fHandle;
3081}
3082
3083std::unique_ptr<SkCanvas>
3084SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3085 const SkImageInfo& info, const Rec* rec) {
3086 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
3087 return nullptr;
3088 }
3089
3090 SkBitmap bm;
3091 Handle hndl;
3092
3093 if (rec) {
3094 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3095 } else {
3096 hndl = alloc->allocBitmap(info, &bm);
3097 }
3098 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3099}
3100
3101///////////////////////////////////////////////////////////////////////////////////////////////////
3102