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/SkCanvasPriv.h"
27#include "src/core/SkClipOpPriv.h"
28#include "src/core/SkClipStack.h"
29#include "src/core/SkDraw.h"
30#include "src/core/SkGlyphRun.h"
31#include "src/core/SkImageFilterCache.h"
32#include "src/core/SkImageFilter_Base.h"
33#include "src/core/SkLatticeIter.h"
34#include "src/core/SkMSAN.h"
35#include "src/core/SkMarkerStack.h"
36#include "src/core/SkMatrixPriv.h"
37#include "src/core/SkMatrixUtils.h"
38#include "src/core/SkPaintPriv.h"
39#include "src/core/SkRasterClip.h"
40#include "src/core/SkSpecialImage.h"
41#include "src/core/SkStrikeCache.h"
42#include "src/core/SkTLazy.h"
43#include "src/core/SkTextFormatParams.h"
44#include "src/core/SkTraceEvent.h"
45#include "src/core/SkVerticesPriv.h"
46#include "src/image/SkImage_Base.h"
47#include "src/image/SkSurface_Base.h"
48#include "src/utils/SkPatchUtils.h"
49
50#include <memory>
51#include <new>
52
53#if SK_SUPPORT_GPU
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
195 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed)
196 : fNext(nullptr)
197 , fDevice(std::move(device))
198 , fPaint(paint ? std::make_unique<SkPaint>(*paint) : nullptr)
199 , fStashedMatrix(stashed)
200 {}
201
202 void reset(const SkIRect& bounds) {
203 SkASSERT(!fPaint);
204 SkASSERT(!fNext);
205 SkASSERT(fDevice);
206 fClip.setRect(bounds);
207 }
208};
209
210namespace {
211// Encapsulate state needed to restore from saveBehind()
212struct BackImage {
213 sk_sp<SkSpecialImage> fImage;
214 SkIPoint fLoc;
215};
216} // namespace
217
218/* This is the record we keep for each save/restore level in the stack.
219 Since a level optionally copies the matrix and/or stack, we have pointers
220 for these fields. If the value is copied for this level, the copy is
221 stored in the ...Storage field, and the pointer points to that. If the
222 value is not copied for this level, we ignore ...Storage, and just point
223 at the corresponding value in the previous level in the stack.
224*/
225class SkCanvas::MCRec {
226public:
227 DeviceCM* fLayer;
228 /* If there are any layers in the stack, this points to the top-most
229 one that is at or below this level in the stack (so we know what
230 bitmap/device to draw into from this level. This value is NOT
231 reference counted, since the real owner is either our fLayer field,
232 or a previous one in a lower level.)
233 */
234 DeviceCM* fTopLayer;
235 std::unique_ptr<BackImage> fBackImage;
236 SkConservativeClip fRasterClip;
237 SkM44 fMatrix;
238 int fDeferredSaveCount;
239
240 MCRec() {
241 fLayer = nullptr;
242 fTopLayer = nullptr;
243 fMatrix.setIdentity();
244 fDeferredSaveCount = 0;
245
246 // don't bother initializing fNext
247 inc_rec();
248 }
249 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
250 fLayer = nullptr;
251 fTopLayer = prev.fTopLayer;
252 fDeferredSaveCount = 0;
253
254 // don't bother initializing fNext
255 inc_rec();
256 }
257 ~MCRec() {
258 delete fLayer;
259 dec_rec();
260 }
261
262 void reset(const SkIRect& bounds) {
263 SkASSERT(fLayer);
264 SkASSERT(fDeferredSaveCount == 0);
265
266 fMatrix.setIdentity();
267 fRasterClip.setRect(bounds);
268 fLayer->reset(bounds);
269 }
270};
271
272class SkDrawIter {
273public:
274 SkDrawIter(SkCanvas* canvas)
275 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
276 {}
277
278 bool next() {
279 const DeviceCM* rec = fCurrLayer;
280 if (rec && rec->fDevice) {
281 fDevice = rec->fDevice.get();
282 fPaint = rec->fPaint.get();
283 fCurrLayer = rec->fNext;
284 // fCurrLayer may be nullptr now
285 return true;
286 }
287 return false;
288 }
289
290 const SkPaint* getPaint() const { return fPaint; }
291
292 SkBaseDevice* fDevice;
293
294private:
295 const DeviceCM* fCurrLayer;
296 const SkPaint* fPaint; // May be null.
297};
298
299#define FOR_EACH_TOP_DEVICE( code ) \
300 do { \
301 DeviceCM* layer = fMCRec->fTopLayer; \
302 while (layer) { \
303 SkBaseDevice* device = layer->fDevice.get(); \
304 if (device) { \
305 code; \
306 } \
307 layer = layer->fNext; \
308 } \
309 } while (0)
310
311/////////////////////////////////////////////////////////////////////////////
312
313/**
314 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
315 * colorfilter, else return nullptr.
316 */
317static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
318 SkImageFilter* imgf = paint.getImageFilter();
319 if (!imgf) {
320 return nullptr;
321 }
322
323 SkColorFilter* imgCFPtr;
324 if (!imgf->asAColorFilter(&imgCFPtr)) {
325 return nullptr;
326 }
327 sk_sp<SkColorFilter> imgCF(imgCFPtr);
328
329 SkColorFilter* paintCF = paint.getColorFilter();
330 if (nullptr == paintCF) {
331 // there is no existing paint colorfilter, so we can just return the imagefilter's
332 return imgCF;
333 }
334
335 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
336 // and we need to combine them into a single colorfilter.
337 return imgCF->makeComposed(sk_ref_sp(paintCF));
338}
339
340/**
341 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
342 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
343 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
344 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
345 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
346 * conservative "effective" bounds based on the settings in the paint... with one exception. This
347 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
348 * deliberately ignored.
349 */
350static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
351 const SkRect& rawBounds,
352 SkRect* storage) {
353 SkPaint tmpUnfiltered(paint);
354 tmpUnfiltered.setImageFilter(nullptr);
355 if (tmpUnfiltered.canComputeFastBounds()) {
356 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
357 } else {
358 return rawBounds;
359 }
360}
361
362class AutoLayerForImageFilter {
363public:
364 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
365 // paint. It's used to determine the size of the offscreen layer for filters.
366 // If null, the clip will be used instead.
367 AutoLayerForImageFilter(SkCanvas* canvas, const SkPaint& origPaint,
368 bool skipLayerForImageFilter = false,
369 const SkRect* rawBounds = nullptr) {
370 fCanvas = canvas;
371 fPaint = &origPaint;
372 fSaveCount = canvas->getSaveCount();
373 fTempLayerForImageFilter = false;
374
375 if (auto simplifiedCF = image_to_color_filter(origPaint)) {
376 SkASSERT(!fLazyPaint.isValid());
377 SkPaint* paint = fLazyPaint.set(origPaint);
378 paint->setColorFilter(std::move(simplifiedCF));
379 paint->setImageFilter(nullptr);
380 fPaint = paint;
381 }
382
383 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
384 /**
385 * We implement ImageFilters for a given draw by creating a layer, then applying the
386 * imagefilter to the pixels of that layer (its backing surface/image), and then
387 * we call restore() to xfer that layer to the main canvas.
388 *
389 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
390 * 2. Generate the src pixels:
391 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
392 * return (fPaint). We then draw the primitive (using srcover) into a cleared
393 * buffer/surface.
394 * 3. Restore the layer created in #1
395 * The imagefilter is passed the buffer/surface from the layer (now filled with the
396 * src pixels of the primitive). It returns a new "filtered" buffer, which we
397 * draw onto the previous layer using the xfermode from the original paint.
398 */
399
400 SkPaint restorePaint;
401 restorePaint.setImageFilter(fPaint->refImageFilter());
402 restorePaint.setBlendMode(fPaint->getBlendMode());
403
404 SkRect storage;
405 if (rawBounds) {
406 // Make rawBounds include all paint outsets except for those due to image filters.
407 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
408 }
409 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &restorePaint),
410 SkCanvas::kFullLayer_SaveLayerStrategy);
411 fTempLayerForImageFilter = true;
412
413 // Remove the restorePaint fields from our "working" paint
414 SkASSERT(!fLazyPaint.isValid());
415 SkPaint* paint = fLazyPaint.set(origPaint);
416 paint->setImageFilter(nullptr);
417 paint->setBlendMode(SkBlendMode::kSrcOver);
418 fPaint = paint;
419 }
420 }
421
422 ~AutoLayerForImageFilter() {
423 if (fTempLayerForImageFilter) {
424 fCanvas->internalRestore();
425 }
426 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
427 }
428
429 const SkPaint& paint() const {
430 SkASSERT(fPaint);
431 return *fPaint;
432 }
433
434private:
435 SkLazyPaint fLazyPaint; // base paint storage in case we need to modify it
436 SkCanvas* fCanvas;
437 const SkPaint* fPaint; // points to either the original paint, or lazy (if we needed it)
438 int fSaveCount;
439 bool fTempLayerForImageFilter;
440};
441
442////////// macros to place around the internal draw calls //////////////////
443
444#define DRAW_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
445 this->predrawNotify(); \
446 AutoLayerForImageFilter draw(this, paint, skipLayerForFilter, bounds); \
447 { SkDrawIter iter(this);
448
449
450#define DRAW_BEGIN_DRAWDEVICE(paint) \
451 this->predrawNotify(); \
452 AutoLayerForImageFilter draw(this, paint, true); \
453 { SkDrawIter iter(this);
454
455#define DRAW_BEGIN(paint, bounds) \
456 this->predrawNotify(); \
457 AutoLayerForImageFilter draw(this, paint, false, bounds); \
458 { SkDrawIter iter(this);
459
460#define DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
461 this->predrawNotify(bounds, &paint, auxOpaque); \
462 AutoLayerForImageFilter draw(this, paint, false, bounds); \
463 { SkDrawIter iter(this);
464
465#define DRAW_END }
466
467////////////////////////////////////////////////////////////////////////////
468
469static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
470 if (bounds.isEmpty()) {
471 return SkRect::MakeEmpty();
472 }
473
474 // Expand bounds out by 1 in case we are anti-aliasing. We store the
475 // bounds as floats to enable a faster quick reject implementation.
476 SkRect dst;
477 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
478 return dst;
479}
480
481void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
482 this->restoreToCount(1);
483 fMCRec->reset(bounds);
484
485 // We're peering through a lot of structs here. Only at this scope do we
486 // know that the device is a SkNoPixelsDevice.
487 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
488 fDeviceClipBounds = qr_clip_bounds(bounds);
489 fIsScaleTranslate = true;
490}
491
492void SkCanvas::init(sk_sp<SkBaseDevice> device) {
493 fMarkerStack = sk_make_sp<SkMarkerStack>();
494
495 fSaveCount = 1;
496
497 fMCRec = (MCRec*)fMCStack.push_back();
498 new (fMCRec) MCRec;
499 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
500 fIsScaleTranslate = true;
501
502 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
503 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
504 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix.asM33());
505
506 fMCRec->fTopLayer = fMCRec->fLayer;
507
508 fSurfaceBase = nullptr;
509 fDeviceClipBounds = {0, 0, 0, 0};
510
511 if (device) {
512 // The root device and the canvas should always have the same pixel geometry
513 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
514 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
515 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
516
517 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
518
519 device->setMarkerStack(fMarkerStack.get());
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 // safety 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.asM33(); // 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);
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::Scale(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.asM33();
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 = SkM44(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 SkBaseDevice* priorDevice = this->getTopDevice();
1145 if (nullptr == priorDevice) { // Do we still need this check???
1146 SkDebugf("Unable to find device for layer.");
1147 return;
1148 }
1149
1150 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
1151 if (rec.fSaveLayerFlags & kF16ColorType) {
1152 info = info.makeColorType(kRGBA_F16_SkColorType);
1153 }
1154
1155 sk_sp<SkBaseDevice> newDevice;
1156 {
1157 SkASSERT(info.alphaType() != kOpaque_SkAlphaType);
1158
1159 SkPixelGeometry geo = saveLayerFlags & kPreserveLCDText_SaveLayerFlag
1160 ? fProps.pixelGeometry()
1161 : kUnknown_SkPixelGeometry;
1162 const bool trackCoverage =
1163 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
1164 const auto createInfo = SkBaseDevice::CreateInfo(info,
1165 geo,
1166 SkBaseDevice::kNever_TileUsage,
1167 trackCoverage,
1168 fAllocator.get());
1169 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1170 if (!newDevice) {
1171 return;
1172 }
1173 newDevice->setMarkerStack(fMarkerStack.get());
1174 }
1175 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix);
1176
1177 // only have a "next" if this new layer doesn't affect the clip (rare)
1178 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
1179 fMCRec->fLayer = layer;
1180 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
1181
1182 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
1183 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
1184 fMCRec->fMatrix.asM33());
1185 }
1186
1187 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1188
1189 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1190 if (layer->fNext) {
1191 // need to punch a hole in the previous device, so we don't draw there, given that
1192 // the new top-layer will allow drawing to happen "below" it.
1193 SkRegion hole(ir);
1194 do {
1195 layer = layer->fNext;
1196 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1197 } while (layer->fNext);
1198 }
1199}
1200
1201int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1202 if (0xFF == alpha) {
1203 return this->saveLayer(bounds, nullptr);
1204 } else {
1205 SkPaint tmpPaint;
1206 tmpPaint.setAlpha(alpha);
1207 return this->saveLayer(bounds, &tmpPaint);
1208 }
1209}
1210
1211void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1212 SkBaseDevice* device = this->getTopDevice();
1213 if (nullptr == device) { // Do we still need this check???
1214 return;
1215 }
1216
1217 // Map the local bounds into the top device's coordinate space (this is not
1218 // necessarily the full global CTM transform).
1219 SkIRect devBounds;
1220 if (localBounds) {
1221 SkRect tmp;
1222 device->localToDevice().mapRect(&tmp, *localBounds);
1223 if (!devBounds.intersect(tmp.round(), device->devClipBounds())) {
1224 devBounds.setEmpty();
1225 }
1226 } else {
1227 devBounds = device->devClipBounds();
1228 }
1229 if (devBounds.isEmpty()) {
1230 return;
1231 }
1232
1233 // This is getting the special image from the current device, which is then drawn into (both by
1234 // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its
1235 // own device, we need to explicitly copy the back image contents so that its original content
1236 // is available when we splat it back later during restore.
1237 auto backImage = device->snapSpecial(devBounds, /* copy */ true);
1238 if (!backImage) {
1239 return;
1240 }
1241
1242 // we really need the save, so we can wack the fMCRec
1243 this->checkForDeferredSave();
1244
1245 fMCRec->fBackImage =
1246 std::make_unique<BackImage>(BackImage{std::move(backImage), devBounds.topLeft()});
1247
1248 SkPaint paint;
1249 paint.setBlendMode(SkBlendMode::kClear);
1250 this->drawClippedToSaveBehind(paint);
1251}
1252
1253void SkCanvas::internalRestore() {
1254 SkASSERT(fMCStack.count() != 0);
1255
1256 // reserve our layer (if any)
1257 DeviceCM* layer = fMCRec->fLayer; // may be null
1258 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1259 fMCRec->fLayer = nullptr;
1260
1261 // move this out before we do the actual restore
1262 auto backImage = std::move(fMCRec->fBackImage);
1263
1264 fMarkerStack->restore(fMCRec);
1265
1266 // now do the normal restore()
1267 fMCRec->~MCRec(); // balanced in save()
1268 fMCStack.pop_back();
1269 fMCRec = (MCRec*)fMCStack.back();
1270
1271 if (fMCRec) {
1272 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1273 }
1274
1275 if (backImage) {
1276 SkPaint paint;
1277 paint.setBlendMode(SkBlendMode::kDstOver);
1278 const int x = backImage->fLoc.x();
1279 const int y = backImage->fLoc.y();
1280 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint);
1281 }
1282
1283 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1284 since if we're being recorded, we don't want to record this (the
1285 recorder will have already recorded the restore).
1286 */
1287 if (layer) {
1288 if (fMCRec) {
1289 layer->fDevice->setImmutable();
1290 // At this point, 'layer' has been removed from the device stack, so the devices that
1291 // internalDrawDevice sees are the destinations that 'layer' is drawn into.
1292 this->internalDrawDevice(layer->fDevice.get(), layer->fPaint.get());
1293 // restore what we smashed in internalSaveLayer
1294 this->internalSetMatrix(layer->fStashedMatrix);
1295 delete layer;
1296 } else {
1297 // we're at the root
1298 SkASSERT(layer == (void*)fDeviceCMStorage);
1299 layer->~DeviceCM();
1300 // no need to update fMCRec, 'cause we're killing the canvas
1301 }
1302 }
1303
1304 if (fMCRec) {
1305 fIsScaleTranslate = SkMatrixPriv::IsScaleTranslateAsM33(fMCRec->fMatrix);
1306 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1307 }
1308}
1309
1310sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1311 if (nullptr == props) {
1312 props = &fProps;
1313 }
1314 return this->onNewSurface(info, *props);
1315}
1316
1317sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1318 SkBaseDevice* dev = this->getDevice();
1319 return dev ? dev->makeSurface(info, props) : nullptr;
1320}
1321
1322SkImageInfo SkCanvas::imageInfo() const {
1323 return this->onImageInfo();
1324}
1325
1326SkImageInfo SkCanvas::onImageInfo() const {
1327 SkBaseDevice* dev = this->getDevice();
1328 if (dev) {
1329 return dev->imageInfo();
1330 } else {
1331 return SkImageInfo::MakeUnknown(0, 0);
1332 }
1333}
1334
1335bool SkCanvas::getProps(SkSurfaceProps* props) const {
1336 return this->onGetProps(props);
1337}
1338
1339bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
1340 SkBaseDevice* dev = this->getDevice();
1341 if (dev) {
1342 if (props) {
1343 *props = fProps;
1344 }
1345 return true;
1346 } else {
1347 return false;
1348 }
1349}
1350
1351bool SkCanvas::peekPixels(SkPixmap* pmap) {
1352 return this->onPeekPixels(pmap);
1353}
1354
1355bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
1356 SkBaseDevice* dev = this->getDevice();
1357 return dev && dev->peekPixels(pmap);
1358}
1359
1360void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1361 SkPixmap pmap;
1362 if (!this->onAccessTopLayerPixels(&pmap)) {
1363 return nullptr;
1364 }
1365 if (info) {
1366 *info = pmap.info();
1367 }
1368 if (rowBytes) {
1369 *rowBytes = pmap.rowBytes();
1370 }
1371 if (origin) {
1372 // If the caller requested the origin, they presumably are expecting the returned pixels to
1373 // be axis-aligned with the root canvas. If the top level device isn't axis aligned, that's
1374 // not the case. Until we update accessTopLayerPixels() to accept a coord space matrix
1375 // instead of an origin, just don't expose the pixels in that case. Note that this means
1376 // that layers with complex coordinate spaces can still report their pixels if the caller
1377 // does not ask for the origin (e.g. just to dump its output to a file, etc).
1378 if (this->getTopDevice()->isPixelAlignedToGlobal()) {
1379 *origin = this->getTopDevice()->getOrigin();
1380 } else {
1381 return nullptr;
1382 }
1383 }
1384 return pmap.writable_addr();
1385}
1386
1387bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
1388 SkBaseDevice* dev = this->getTopDevice();
1389 return dev && dev->accessPixels(pmap);
1390}
1391
1392/////////////////////////////////////////////////////////////////////////////
1393
1394// In our current design/features, we should never have a layer (src) in a different colorspace
1395// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1396// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1397// colorspace.
1398static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1399 SkASSERT(src == dst);
1400}
1401
1402void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, const SkPaint* paint) {
1403 SkPaint tmp;
1404 if (nullptr == paint) {
1405 paint = &tmp;
1406 }
1407
1408 DRAW_BEGIN_DRAWDEVICE(*paint)
1409
1410 while (iter.next()) {
1411 SkBaseDevice* dstDev = iter.fDevice;
1412 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1413 srcDev->imageInfo().colorSpace());
1414 paint = &draw.paint();
1415 SkImageFilter* filter = paint->getImageFilter();
1416 // TODO(michaelludwig) - Devices aren't created with complex coordinate systems yet,
1417 // so it should always be possible to use the relative origin. Once drawDevice() and
1418 // drawSpecial() take an SkMatrix, this can switch to getRelativeTransform() instead.
1419 SkIPoint pos = srcDev->getOrigin() - dstDev->getOrigin();
1420 if (filter) {
1421 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1422 if (specialImage) {
1423 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1424 specialImage->getColorSpace());
1425 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint);
1426 }
1427 } else {
1428 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
1429 }
1430 }
1431
1432 DRAW_END
1433}
1434
1435/////////////////////////////////////////////////////////////////////////////
1436
1437void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1438 if (dx || dy) {
1439 this->checkForDeferredSave();
1440 fMCRec->fMatrix.preTranslate(dx, dy);
1441
1442 // Translate shouldn't affect the is-scale-translateness of the matrix.
1443 // However, if either is non-finite, we might still complicate the matrix type,
1444 // so we still have to compute this.
1445 fIsScaleTranslate = SkMatrixPriv::IsScaleTranslateAsM33(fMCRec->fMatrix);
1446
1447 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1448
1449 this->didTranslate(dx,dy);
1450 }
1451}
1452
1453void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1454 if (sx != 1 || sy != 1) {
1455 this->checkForDeferredSave();
1456 fMCRec->fMatrix.preScale(sx, sy);
1457
1458 // shouldn't need to do this (theoretically), as the state shouldn't have changed,
1459 // but pre-scaling by a non-finite does change it, so we have to recompute.
1460 fIsScaleTranslate = SkMatrixPriv::IsScaleTranslateAsM33(fMCRec->fMatrix);
1461
1462 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1463
1464 this->didScale(sx, sy);
1465 }
1466}
1467
1468void SkCanvas::rotate(SkScalar degrees) {
1469 SkMatrix m;
1470 m.setRotate(degrees);
1471 this->concat(m);
1472}
1473
1474void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1475 SkMatrix m;
1476 m.setRotate(degrees, px, py);
1477 this->concat(m);
1478}
1479
1480void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1481 SkMatrix m;
1482 m.setSkew(sx, sy);
1483 this->concat(m);
1484}
1485
1486void SkCanvas::concat(const SkMatrix& matrix) {
1487 if (matrix.isIdentity()) {
1488 return;
1489 }
1490
1491 this->checkForDeferredSave();
1492 fMCRec->fMatrix.preConcat(matrix);
1493
1494 fIsScaleTranslate = SkMatrixPriv::IsScaleTranslateAsM33(fMCRec->fMatrix);
1495
1496 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1497
1498 this->didConcat(matrix);
1499}
1500
1501void SkCanvas::internalConcat44(const SkM44& m) {
1502 this->checkForDeferredSave();
1503
1504 fMCRec->fMatrix.preConcat(m);
1505
1506 fIsScaleTranslate = SkMatrixPriv::IsScaleTranslateAsM33(fMCRec->fMatrix);
1507
1508 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1509}
1510
1511void SkCanvas::concat(const SkM44& m) {
1512 this->internalConcat44(m);
1513 // notify subclasses
1514 this->didConcat44(m);
1515}
1516
1517void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
1518 fMCRec->fMatrix = SkM44(matrix);
1519 fIsScaleTranslate = matrix.isScaleTranslate();
1520
1521 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1522}
1523
1524void SkCanvas::setMatrix(const SkMatrix& matrix) {
1525 this->checkForDeferredSave();
1526 this->internalSetMatrix(matrix);
1527 this->didSetMatrix(matrix);
1528}
1529
1530void SkCanvas::resetMatrix() {
1531 this->setMatrix(SkMatrix::I());
1532}
1533
1534void SkCanvas::markCTM(const char* name) {
1535 if (SkCanvasPriv::ValidateMarker(name)) {
1536 fMarkerStack->setMarker(SkOpts::hash_fn(name, strlen(name), 0),
1537 this->getLocalToDevice(), fMCRec);
1538 this->onMarkCTM(name);
1539 }
1540}
1541
1542bool SkCanvas::findMarkedCTM(const char* name, SkM44* mx) const {
1543 return SkCanvasPriv::ValidateMarker(name) &&
1544 fMarkerStack->findMarker(SkOpts::hash_fn(name, strlen(name), 0), mx);
1545}
1546
1547//////////////////////////////////////////////////////////////////////////////
1548
1549void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
1550 if (!rect.isFinite()) {
1551 return;
1552 }
1553 this->checkForDeferredSave();
1554 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1555 this->onClipRect(rect, op, edgeStyle);
1556}
1557
1558void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1559 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1560
1561 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
1562
1563 AutoValidateClip avc(this);
1564 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix.asM33(), this->getTopLayerBounds(),
1565 (SkRegion::Op)op, isAA);
1566 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1567}
1568
1569void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1570 fClipRestrictionRect = rect;
1571 if (fClipRestrictionRect.isEmpty()) {
1572 // we notify the device, but we *dont* resolve deferred saves (since we're just
1573 // removing the restriction if the rect is empty. how I hate this api.
1574 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1575 } else {
1576 this->checkForDeferredSave();
1577 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1578 AutoValidateClip avc(this);
1579 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
1580 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1581 }
1582}
1583
1584void SkCanvas::androidFramework_replaceClip(const SkIRect& rect) {
1585 this->checkForDeferredSave();
1586 FOR_EACH_TOP_DEVICE(device->replaceClip(rect));
1587 AutoValidateClip avc(this);
1588 fMCRec->fRasterClip.setRect(rect);
1589 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1590}
1591
1592void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
1593 this->checkForDeferredSave();
1594 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1595 if (rrect.isRect()) {
1596 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1597 } else {
1598 this->onClipRRect(rrect, op, edgeStyle);
1599 }
1600}
1601
1602void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1603 AutoValidateClip avc(this);
1604
1605 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1606
1607 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
1608
1609 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix.asM33(), this->getTopLayerBounds(),
1610 (SkRegion::Op)op, isAA);
1611 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1612}
1613
1614void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
1615 this->checkForDeferredSave();
1616 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1617
1618 if (!path.isInverseFillType() && fMCRec->fMatrix.asM33().rectStaysRect()) {
1619 SkRect r;
1620 if (path.isRect(&r)) {
1621 this->onClipRect(r, op, edgeStyle);
1622 return;
1623 }
1624 SkRRect rrect;
1625 if (path.isOval(&r)) {
1626 rrect.setOval(r);
1627 this->onClipRRect(rrect, op, edgeStyle);
1628 return;
1629 }
1630 if (path.isRRect(&rrect)) {
1631 this->onClipRRect(rrect, op, edgeStyle);
1632 return;
1633 }
1634 }
1635
1636 this->onClipPath(path, op, edgeStyle);
1637}
1638
1639void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
1640 AutoValidateClip avc(this);
1641
1642 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1643
1644 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
1645
1646 const SkPath* rasterClipPath = &path;
1647 fMCRec->fRasterClip.opPath(*rasterClipPath, fMCRec->fMatrix.asM33(), this->getTopLayerBounds(),
1648 (SkRegion::Op)op, isAA);
1649 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1650}
1651
1652void SkCanvas::clipShader(sk_sp<SkShader> sh, SkClipOp op) {
1653 if (sh) {
1654 if (sh->isOpaque()) {
1655 if (op == SkClipOp::kIntersect) {
1656 // we don't occlude anything, so skip this call
1657 } else {
1658 SkASSERT(op == SkClipOp::kDifference);
1659 // we occlude everything, so set the clip to empty
1660 this->clipRect({0,0,0,0});
1661 }
1662 } else {
1663 this->checkForDeferredSave();
1664 this->onClipShader(std::move(sh), op);
1665 }
1666 }
1667}
1668
1669void SkCanvas::onClipShader(sk_sp<SkShader> sh, SkClipOp op) {
1670 AutoValidateClip avc(this);
1671
1672 FOR_EACH_TOP_DEVICE(device->clipShader(sh, op));
1673
1674 // we don't know how to mutate our conservative bounds, so we don't
1675}
1676
1677void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
1678 this->checkForDeferredSave();
1679 this->onClipRegion(rgn, op);
1680}
1681
1682void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
1683 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
1684
1685 AutoValidateClip avc(this);
1686
1687 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
1688 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1689}
1690
1691#ifdef SK_DEBUG
1692void SkCanvas::validateClip() const {
1693 // construct clipRgn from the clipstack
1694 const SkBaseDevice* device = this->getDevice();
1695 if (!device) {
1696 SkASSERT(this->isClipEmpty());
1697 return;
1698 }
1699}
1700#endif
1701
1702bool SkCanvas::androidFramework_isClipAA() const {
1703 bool containsAA = false;
1704
1705 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1706
1707 return containsAA;
1708}
1709
1710class RgnAccumulator {
1711 SkRegion* fRgn;
1712public:
1713 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1714 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1715 SkIPoint origin = device->getOrigin();
1716 if (origin.x() | origin.y()) {
1717 rgn->translate(origin.x(), origin.y());
1718 }
1719 fRgn->op(*rgn, SkRegion::kUnion_Op);
1720 }
1721};
1722
1723void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1724 RgnAccumulator accum(rgn);
1725 SkRegion tmp;
1726
1727 rgn->setEmpty();
1728 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
1729}
1730
1731///////////////////////////////////////////////////////////////////////////////
1732
1733bool SkCanvas::isClipEmpty() const {
1734 return fMCRec->fRasterClip.isEmpty();
1735
1736 // TODO: should we only use the conservative answer in a recording canvas?
1737#if 0
1738 SkBaseDevice* dev = this->getTopDevice();
1739 // if no device we return true
1740 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
1741#endif
1742}
1743
1744bool SkCanvas::isClipRect() const {
1745 SkBaseDevice* dev = this->getTopDevice();
1746 // if no device we return false
1747 return dev && dev->onGetClipType() == SkBaseDevice::ClipType::kRect;
1748}
1749
1750static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1751#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1752 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1753 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1754 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1755 return 0xF != _mm_movemask_ps(mask);
1756#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1757 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1758 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1759 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1760 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1761#else
1762 SkRect devRectAsRect;
1763 SkRect devClipAsRect;
1764 devRect.store(&devRectAsRect.fLeft);
1765 devClip.store(&devClipAsRect.fLeft);
1766 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1767#endif
1768}
1769
1770// It's important for this function to not be inlined. Otherwise the compiler will share code
1771// between the fast path and the slow path, resulting in two slow paths.
1772static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1773 const SkMatrix& matrix) {
1774 SkRect deviceRect;
1775 matrix.mapRect(&deviceRect, src);
1776 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1777}
1778
1779bool SkCanvas::quickReject(const SkRect& src) const {
1780#ifdef SK_DEBUG
1781 // Verify that fDeviceClipBounds are set properly.
1782 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1783 if (fMCRec->fRasterClip.isEmpty()) {
1784 SkASSERT(fDeviceClipBounds.isEmpty());
1785 } else {
1786 SkASSERT(tmp == fDeviceClipBounds);
1787 }
1788
1789 // Verify that fIsScaleTranslate is set properly.
1790 SkASSERT(fIsScaleTranslate == SkMatrixPriv::IsScaleTranslateAsM33(fMCRec->fMatrix));
1791#endif
1792
1793 if (!fIsScaleTranslate) {
1794 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix.asM33());
1795 }
1796
1797 // We inline the implementation of mapScaleTranslate() for the fast path.
1798 float sx = fMCRec->fMatrix.rc(0, 0);
1799 float sy = fMCRec->fMatrix.rc(1, 1);
1800 float tx = fMCRec->fMatrix.rc(0, 3);
1801 float ty = fMCRec->fMatrix.rc(1, 3);
1802 Sk4f scale(sx, sy, sx, sy);
1803 Sk4f trans(tx, ty, tx, ty);
1804
1805 // Apply matrix.
1806 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1807
1808 // Make sure left < right, top < bottom.
1809 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1810 Sk4f min = Sk4f::Min(ltrb, rblt);
1811 Sk4f max = Sk4f::Max(ltrb, rblt);
1812 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1813 // ARM this sequence generates the fastest (a single instruction).
1814 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1815
1816 // Check if the device rect is NaN or outside the clip.
1817 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
1818}
1819
1820bool SkCanvas::quickReject(const SkPath& path) const {
1821 return path.isEmpty() || this->quickReject(path.getBounds());
1822}
1823
1824SkRect SkCanvas::getLocalClipBounds() const {
1825 SkIRect ibounds = this->getDeviceClipBounds();
1826 if (ibounds.isEmpty()) {
1827 return SkRect::MakeEmpty();
1828 }
1829
1830 SkMatrix inverse;
1831 // if we can't invert the CTM, we can't return local clip bounds
1832 if (!fMCRec->fMatrix.asM33().invert(&inverse)) {
1833 return SkRect::MakeEmpty();
1834 }
1835
1836 SkRect bounds;
1837 // adjust it outwards in case we are antialiasing
1838 const int margin = 1;
1839
1840 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
1841 inverse.mapRect(&bounds, r);
1842 return bounds;
1843}
1844
1845SkIRect SkCanvas::getDeviceClipBounds() const {
1846 return fMCRec->fRasterClip.getBounds();
1847}
1848
1849///////////////////////////////////////////////////////////////////////
1850
1851SkMatrix SkCanvas::getTotalMatrix() const {
1852 return fMCRec->fMatrix.asM33();
1853}
1854
1855SkM44 SkCanvas::getLocalToDevice() const {
1856 return fMCRec->fMatrix;
1857}
1858
1859GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
1860 SkBaseDevice* dev = this->getTopDevice();
1861 return dev ? dev->accessRenderTargetContext() : nullptr;
1862}
1863
1864GrContext* SkCanvas::getGrContext() {
1865 SkBaseDevice* device = this->getTopDevice();
1866 return device ? device->context() : nullptr;
1867}
1868
1869GrRecordingContext* SkCanvas::recordingContext() {
1870 SkBaseDevice* device = this->getTopDevice();
1871 return device ? device->recordingContext() : nullptr;
1872}
1873
1874void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1875 const SkPaint& paint) {
1876 TRACE_EVENT0("skia", TRACE_FUNC);
1877 if (outer.isEmpty()) {
1878 return;
1879 }
1880 if (inner.isEmpty()) {
1881 this->drawRRect(outer, paint);
1882 return;
1883 }
1884
1885 // We don't have this method (yet), but technically this is what we should
1886 // be able to return ...
1887 // if (!outer.contains(inner))) {
1888 //
1889 // For now at least check for containment of bounds
1890 if (!outer.getBounds().contains(inner.getBounds())) {
1891 return;
1892 }
1893
1894 this->onDrawDRRect(outer, inner, paint);
1895}
1896
1897void SkCanvas::drawPaint(const SkPaint& paint) {
1898 TRACE_EVENT0("skia", TRACE_FUNC);
1899 this->onDrawPaint(paint);
1900}
1901
1902void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1903 TRACE_EVENT0("skia", TRACE_FUNC);
1904 // To avoid redundant logic in our culling code and various backends, we always sort rects
1905 // before passing them along.
1906 this->onDrawRect(r.makeSorted(), paint);
1907}
1908
1909void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1910 TRACE_EVENT0("skia", TRACE_FUNC);
1911 this->onDrawBehind(paint);
1912}
1913
1914void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1915 TRACE_EVENT0("skia", TRACE_FUNC);
1916 if (region.isEmpty()) {
1917 return;
1918 }
1919
1920 if (region.isRect()) {
1921 return this->drawIRect(region.getBounds(), paint);
1922 }
1923
1924 this->onDrawRegion(region, paint);
1925}
1926
1927void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1928 TRACE_EVENT0("skia", TRACE_FUNC);
1929 // To avoid redundant logic in our culling code and various backends, we always sort rects
1930 // before passing them along.
1931 this->onDrawOval(r.makeSorted(), paint);
1932}
1933
1934void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1935 TRACE_EVENT0("skia", TRACE_FUNC);
1936 this->onDrawRRect(rrect, paint);
1937}
1938
1939void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1940 TRACE_EVENT0("skia", TRACE_FUNC);
1941 this->onDrawPoints(mode, count, pts, paint);
1942}
1943
1944void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1945 const SkPaint& paint) {
1946 this->drawVertices(vertices.get(), mode, paint);
1947}
1948
1949void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1950 TRACE_EVENT0("skia", TRACE_FUNC);
1951 RETURN_ON_NULL(vertices);
1952
1953 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1954 SkASSERT(vertices->priv().mode() != SkVertices::kTriangleFan_VertexMode);
1955
1956 // If the vertices contain custom attributes, ensure they line up with the paint's shader.
1957 const SkRuntimeEffect* effect =
1958 paint.getShader() ? as_SB(paint.getShader())->asRuntimeEffect() : nullptr;
1959 if ((size_t)vertices->priv().attributeCount() != (effect ? effect->varyings().count() : 0)) {
1960 return;
1961 }
1962 if (effect) {
1963 int attrIndex = 0;
1964 for (const auto& v : effect->varyings()) {
1965 const SkVertices::Attribute& attr(vertices->priv().attributes()[attrIndex++]);
1966 // Mismatch between the SkSL varying and the vertex shader output for this attribute
1967 if (attr.channelCount() != v.fWidth) {
1968 return;
1969 }
1970 // If we can't provide any of the asked-for matrices, we can't draw this
1971 if (attr.fMarkerID && !fMarkerStack->findMarker(attr.fMarkerID, nullptr)) {
1972 return;
1973 }
1974 }
1975 }
1976
1977#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1978 // Preserve legacy behavior for Android: ignore the SkShader if there are no texCoords present
1979 if (paint.getShader() &&
1980 !(vertices->priv().hasTexCoords() || vertices->priv().hasCustomData())) {
1981 SkPaint noShaderPaint(paint);
1982 noShaderPaint.setShader(nullptr);
1983 this->onDrawVerticesObject(vertices, mode, noShaderPaint);
1984 return;
1985 }
1986#endif
1987
1988 this->onDrawVerticesObject(vertices, mode, paint);
1989}
1990
1991void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1992 TRACE_EVENT0("skia", TRACE_FUNC);
1993 this->onDrawPath(path, paint);
1994}
1995
1996void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1997 TRACE_EVENT0("skia", TRACE_FUNC);
1998 RETURN_ON_NULL(image);
1999 this->onDrawImage(image, x, y, paint);
2000}
2001
2002// Returns true if the rect can be "filled" : non-empty and finite
2003static bool fillable(const SkRect& r) {
2004 SkScalar w = r.width();
2005 SkScalar h = r.height();
2006 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
2007}
2008
2009void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
2010 const SkPaint* paint, SrcRectConstraint constraint) {
2011 TRACE_EVENT0("skia", TRACE_FUNC);
2012 RETURN_ON_NULL(image);
2013 if (!fillable(dst) || !fillable(src)) {
2014 return;
2015 }
2016 this->onDrawImageRect(image, &src, dst, paint, constraint);
2017}
2018
2019void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
2020 const SkPaint* paint, SrcRectConstraint constraint) {
2021 RETURN_ON_NULL(image);
2022 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
2023}
2024
2025void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
2026 RETURN_ON_NULL(image);
2027 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
2028 kFast_SrcRectConstraint);
2029}
2030
2031namespace {
2032class LatticePaint : SkNoncopyable {
2033public:
2034 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
2035 if (!origPaint) {
2036 return;
2037 }
2038 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
2039 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
2040 }
2041 if (origPaint->getMaskFilter()) {
2042 fPaint.writable()->setMaskFilter(nullptr);
2043 }
2044 if (origPaint->isAntiAlias()) {
2045 fPaint.writable()->setAntiAlias(false);
2046 }
2047 }
2048
2049 const SkPaint* get() const {
2050 return fPaint;
2051 }
2052
2053private:
2054 SkTCopyOnFirstWrite<SkPaint> fPaint;
2055};
2056} // namespace
2057
2058void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2059 const SkPaint* paint) {
2060 TRACE_EVENT0("skia", TRACE_FUNC);
2061 RETURN_ON_NULL(image);
2062 if (dst.isEmpty()) {
2063 return;
2064 }
2065 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2066 LatticePaint latticePaint(paint);
2067 this->onDrawImageNine(image, center, dst, latticePaint.get());
2068 } else {
2069 this->drawImageRect(image, dst, paint);
2070 }
2071}
2072
2073void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2074 const SkPaint* paint) {
2075 TRACE_EVENT0("skia", TRACE_FUNC);
2076 RETURN_ON_NULL(image);
2077 if (dst.isEmpty()) {
2078 return;
2079 }
2080
2081 SkIRect bounds;
2082 Lattice latticePlusBounds = lattice;
2083 if (!latticePlusBounds.fBounds) {
2084 bounds = SkIRect::MakeWH(image->width(), image->height());
2085 latticePlusBounds.fBounds = &bounds;
2086 }
2087
2088 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
2089 LatticePaint latticePaint(paint);
2090 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
2091 } else {
2092 this->drawImageRect(image, dst, paint);
2093 }
2094}
2095
2096static sk_sp<SkImage> bitmap_as_image(const SkBitmap& bitmap) {
2097 if (bitmap.drawsNothing()) {
2098 return nullptr;
2099 }
2100 return SkImage::MakeFromBitmap(bitmap);
2101}
2102
2103void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
2104 this->drawImage(bitmap_as_image(bitmap), dx, dy, paint);
2105}
2106
2107void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
2108 const SkPaint* paint, SrcRectConstraint constraint) {
2109 this->drawImageRect(bitmap_as_image(bitmap), src, dst, paint, constraint);
2110}
2111
2112void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2113 const SkPaint* paint, SrcRectConstraint constraint) {
2114 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
2115}
2116
2117void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2118 SrcRectConstraint constraint) {
2119 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2120 constraint);
2121}
2122
2123void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2124 const SkColor colors[], int count, SkBlendMode mode,
2125 const SkRect* cull, const SkPaint* paint) {
2126 TRACE_EVENT0("skia", TRACE_FUNC);
2127 RETURN_ON_NULL(atlas);
2128 if (count <= 0) {
2129 return;
2130 }
2131 SkASSERT(atlas);
2132 SkASSERT(tex);
2133 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2134}
2135
2136void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2137 TRACE_EVENT0("skia", TRACE_FUNC);
2138 if (key) {
2139 this->onDrawAnnotation(rect, key, value);
2140 }
2141}
2142
2143void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2144 const SkPaint* paint, SrcRectConstraint constraint) {
2145 if (src) {
2146 this->drawImageRect(image, *src, dst, paint, constraint);
2147 } else {
2148 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2149 dst, paint, constraint);
2150 }
2151}
2152
2153void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
2154 TRACE_EVENT0("skia", TRACE_FUNC);
2155 this->onDrawShadowRec(path, rec);
2156}
2157
2158void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
2159 SkPaint paint;
2160 const SkRect& pathBounds = path.getBounds();
2161
2162 DRAW_BEGIN(paint, &pathBounds)
2163 while (iter.next()) {
2164 iter.fDevice->drawShadow(path, rec);
2165 }
2166 DRAW_END
2167}
2168
2169void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2170 QuadAAFlags aaFlags, const SkColor4f& color,
2171 SkBlendMode mode) {
2172 TRACE_EVENT0("skia", TRACE_FUNC);
2173 // Make sure the rect is sorted before passing it along
2174 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2175}
2176
2177void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2178 const SkPoint dstClips[],
2179 const SkMatrix preViewMatrices[],
2180 const SkPaint* paint,
2181 SrcRectConstraint constraint) {
2182 TRACE_EVENT0("skia", TRACE_FUNC);
2183 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2184}
2185
2186//////////////////////////////////////////////////////////////////////////////
2187// These are the virtual drawing methods
2188//////////////////////////////////////////////////////////////////////////////
2189
2190void SkCanvas::onDiscard() {
2191 if (fSurfaceBase) {
2192 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2193 }
2194}
2195
2196void SkCanvas::onDrawPaint(const SkPaint& paint) {
2197 this->internalDrawPaint(paint);
2198}
2199
2200void SkCanvas::internalDrawPaint(const SkPaint& paint) {
2201 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
2202
2203 while (iter.next()) {
2204 iter.fDevice->drawPaint(draw.paint());
2205 }
2206
2207 DRAW_END
2208}
2209
2210void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2211 const SkPaint& paint) {
2212 if ((long)count <= 0) {
2213 return;
2214 }
2215
2216 SkRect r;
2217 const SkRect* bounds = nullptr;
2218 if (paint.canComputeFastBounds()) {
2219 // special-case 2 points (common for drawing a single line)
2220 if (2 == count) {
2221 r.set(pts[0], pts[1]);
2222 } else {
2223 r.setBounds(pts, SkToInt(count));
2224 }
2225 if (!r.isFinite()) {
2226 return;
2227 }
2228 SkRect storage;
2229 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2230 return;
2231 }
2232 bounds = &r;
2233 }
2234
2235 SkASSERT(pts != nullptr);
2236
2237 DRAW_BEGIN(paint, bounds)
2238
2239 while (iter.next()) {
2240 iter.fDevice->drawPoints(mode, count, pts, draw.paint());
2241 }
2242
2243 DRAW_END
2244}
2245
2246static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2247 return paint.getImageFilter() != nullptr;
2248}
2249
2250void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
2251 SkASSERT(r.isSorted());
2252 if (paint.canComputeFastBounds()) {
2253 SkRect storage;
2254 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2255 return;
2256 }
2257 }
2258
2259 if (needs_autodrawlooper(this, paint)) {
2260 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
2261
2262 while (iter.next()) {
2263 iter.fDevice->drawRect(r, draw.paint());
2264 }
2265
2266 DRAW_END
2267 } else if (!paint.nothingToDraw()) {
2268 this->predrawNotify(&r, &paint, false);
2269 SkDrawIter iter(this);
2270 while (iter.next()) {
2271 iter.fDevice->drawRect(r, paint);
2272 }
2273 }
2274}
2275
2276void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2277 SkRect regionRect = SkRect::Make(region.getBounds());
2278 if (paint.canComputeFastBounds()) {
2279 SkRect storage;
2280 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2281 return;
2282 }
2283 }
2284
2285 DRAW_BEGIN(paint, &regionRect)
2286
2287 while (iter.next()) {
2288 iter.fDevice->drawRegion(region, draw.paint());
2289 }
2290
2291 DRAW_END
2292}
2293
2294void SkCanvas::onDrawBehind(const SkPaint& paint) {
2295 SkIRect bounds;
2296 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2297 for (;;) {
2298 const MCRec* rec = (const MCRec*)iter.prev();
2299 if (!rec) {
2300 return; // no backimages, so nothing to draw
2301 }
2302 if (rec->fBackImage) {
2303 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2304 rec->fBackImage->fImage->width(),
2305 rec->fBackImage->fImage->height());
2306 break;
2307 }
2308 }
2309
2310 DRAW_BEGIN(paint, nullptr)
2311
2312 while (iter.next()) {
2313 SkBaseDevice* dev = iter.fDevice;
2314
2315 dev->save();
2316 // We use clipRegion because it is already defined to operate in dev-space
2317 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2318 // but we don't want that, so we undo that before calling in.
2319 SkRegion rgn(bounds.makeOffset(dev->getOrigin()));
2320 dev->clipRegion(rgn, SkClipOp::kIntersect);
2321 dev->drawPaint(draw.paint());
2322 dev->restore(fMCRec->fMatrix);
2323 }
2324
2325 DRAW_END
2326}
2327
2328void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
2329 SkASSERT(oval.isSorted());
2330 if (paint.canComputeFastBounds()) {
2331 SkRect storage;
2332 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2333 return;
2334 }
2335 }
2336
2337 DRAW_BEGIN(paint, &oval)
2338
2339 while (iter.next()) {
2340 iter.fDevice->drawOval(oval, draw.paint());
2341 }
2342
2343 DRAW_END
2344}
2345
2346void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2347 SkScalar sweepAngle, bool useCenter,
2348 const SkPaint& paint) {
2349 SkASSERT(oval.isSorted());
2350 if (paint.canComputeFastBounds()) {
2351 SkRect storage;
2352 // Note we're using the entire oval as the bounds.
2353 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2354 return;
2355 }
2356 }
2357
2358 DRAW_BEGIN(paint, &oval)
2359
2360 while (iter.next()) {
2361 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, draw.paint());
2362 }
2363
2364 DRAW_END
2365}
2366
2367void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
2368 if (paint.canComputeFastBounds()) {
2369 SkRect storage;
2370 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2371 return;
2372 }
2373 }
2374
2375 if (rrect.isRect()) {
2376 // call the non-virtual version
2377 this->SkCanvas::drawRect(rrect.getBounds(), paint);
2378 return;
2379 } else if (rrect.isOval()) {
2380 // call the non-virtual version
2381 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2382 return;
2383 }
2384
2385 DRAW_BEGIN(paint, &rrect.getBounds())
2386
2387 while (iter.next()) {
2388 iter.fDevice->drawRRect(rrect, draw.paint());
2389 }
2390
2391 DRAW_END
2392}
2393
2394void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
2395 if (paint.canComputeFastBounds()) {
2396 SkRect storage;
2397 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2398 return;
2399 }
2400 }
2401
2402 DRAW_BEGIN(paint, &outer.getBounds())
2403
2404 while (iter.next()) {
2405 iter.fDevice->drawDRRect(outer, inner, draw.paint());
2406 }
2407
2408 DRAW_END
2409}
2410
2411void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
2412 if (!path.isFinite()) {
2413 return;
2414 }
2415
2416 const SkRect& pathBounds = path.getBounds();
2417 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
2418 SkRect storage;
2419 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2420 return;
2421 }
2422 }
2423
2424 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
2425 if (path.isInverseFillType()) {
2426 this->internalDrawPaint(paint);
2427 return;
2428 }
2429 }
2430
2431 DRAW_BEGIN(paint, &pathBounds)
2432
2433 while (iter.next()) {
2434 iter.fDevice->drawPath(path, draw.paint());
2435 }
2436
2437 DRAW_END
2438}
2439
2440bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
2441 if (!paint.getImageFilter()) {
2442 return false;
2443 }
2444
2445 const SkMatrix& ctm = this->getTotalMatrix();
2446 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
2447 return false;
2448 }
2449
2450 // The other paint effects need to be applied before the image filter, but the sprite draw
2451 // applies the filter explicitly first.
2452 if (paint.getAlphaf() < 1.f || paint.getColorFilter() || paint.getMaskFilter()) {
2453 return false;
2454 }
2455 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2456 // Once we can filter and the filter will return a result larger than itself, we should be
2457 // able to remove this constraint.
2458 // skbug.com/4526
2459 //
2460 SkPoint pt;
2461 ctm.mapXY(x, y, &pt);
2462 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2463 return ir.contains(fMCRec->fRasterClip.getBounds());
2464}
2465
2466// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2467// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2468// null.
2469static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2470 if (paintParam) {
2471 *real = *paintParam;
2472 real->setStyle(SkPaint::kFill_Style);
2473 real->setPathEffect(nullptr);
2474 paintParam = real;
2475 }
2476 return paintParam;
2477}
2478
2479void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
2480 SkPaint realPaint;
2481 paint = init_image_paint(&realPaint, paint);
2482
2483 SkRect bounds = SkRect::MakeXYWH(x, y,
2484 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
2485 if (nullptr == paint || paint->canComputeFastBounds()) {
2486 SkRect tmp = bounds;
2487 if (paint) {
2488 paint->computeFastBounds(tmp, &tmp);
2489 }
2490 if (this->quickReject(tmp)) {
2491 return;
2492 }
2493 }
2494 // At this point we need a real paint object. If the caller passed null, then we should
2495 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2496 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2497 paint = &realPaint;
2498
2499 sk_sp<SkSpecialImage> special;
2500 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2501 *paint);
2502 if (drawAsSprite && paint->getImageFilter()) {
2503 special = this->getDevice()->makeSpecial(image);
2504 if (!special) {
2505 drawAsSprite = false;
2506 }
2507 }
2508
2509 DRAW_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2510
2511 while (iter.next()) {
2512 const SkPaint& pnt = draw.paint();
2513 if (special) {
2514 SkPoint pt;
2515 iter.fDevice->localToDevice().mapXY(x, y, &pt);
2516 iter.fDevice->drawSpecial(special.get(),
2517 SkScalarRoundToInt(pt.fX),
2518 SkScalarRoundToInt(pt.fY), pnt);
2519 } else {
2520 iter.fDevice->drawImageRect(
2521 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2522 kStrict_SrcRectConstraint);
2523 }
2524 }
2525
2526 DRAW_END
2527}
2528
2529void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2530 const SkPaint* paint, SrcRectConstraint constraint) {
2531 SkPaint realPaint;
2532 paint = init_image_paint(&realPaint, paint);
2533
2534 if (nullptr == paint || paint->canComputeFastBounds()) {
2535 SkRect storage = dst;
2536 if (paint) {
2537 paint->computeFastBounds(dst, &storage);
2538 }
2539 if (this->quickReject(storage)) {
2540 return;
2541 }
2542 }
2543 paint = &realPaint;
2544
2545 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
2546
2547 while (iter.next()) {
2548 iter.fDevice->drawImageRect(image, src, dst, draw.paint(), constraint);
2549 }
2550
2551 DRAW_END
2552}
2553
2554void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2555 const SkPaint* paint) {
2556 SkPaint realPaint;
2557 paint = init_image_paint(&realPaint, paint);
2558
2559 if (nullptr == paint || paint->canComputeFastBounds()) {
2560 SkRect storage;
2561 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2562 return;
2563 }
2564 }
2565 paint = &realPaint;
2566
2567 DRAW_BEGIN(*paint, &dst)
2568
2569 while (iter.next()) {
2570 iter.fDevice->drawImageNine(image, center, dst, draw.paint());
2571 }
2572
2573 DRAW_END
2574}
2575
2576void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2577 const SkPaint* paint) {
2578 SkPaint realPaint;
2579 paint = init_image_paint(&realPaint, paint);
2580
2581 if (nullptr == paint || paint->canComputeFastBounds()) {
2582 SkRect storage;
2583 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2584 return;
2585 }
2586 }
2587 paint = &realPaint;
2588
2589 DRAW_BEGIN(*paint, &dst)
2590
2591 while (iter.next()) {
2592 iter.fDevice->drawImageLattice(image, lattice, dst, draw.paint());
2593 }
2594
2595 DRAW_END
2596}
2597
2598void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2599 const SkPaint& paint) {
2600 SkRect storage;
2601 const SkRect* bounds = nullptr;
2602 if (paint.canComputeFastBounds()) {
2603 storage = blob->bounds().makeOffset(x, y);
2604 SkRect tmp;
2605 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2606 return;
2607 }
2608 bounds = &storage;
2609 }
2610
2611 // We cannot filter in the looper as we normally do, because the paint is
2612 // incomplete at this point (text-related attributes are embedded within blob run paints).
2613 DRAW_BEGIN(paint, bounds)
2614
2615 while (iter.next()) {
2616 fScratchGlyphRunBuilder->drawTextBlob(draw.paint(), *blob, {x, y}, iter.fDevice);
2617 }
2618
2619 DRAW_END
2620}
2621
2622// These call the (virtual) onDraw... method
2623void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
2624 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2625 TRACE_EVENT0("skia", TRACE_FUNC);
2626 if (byteLength) {
2627 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
2628 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
2629 }
2630}
2631
2632void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2633 const SkPaint& paint) {
2634 TRACE_EVENT0("skia", TRACE_FUNC);
2635 RETURN_ON_NULL(blob);
2636 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
2637
2638 // Overflow if more than 2^21 glyphs stopping a buffer overflow latter in the stack.
2639 // See chromium:1080481
2640 // TODO: can consider unrolling a few at a time if this limit becomes a problem.
2641 int totalGlyphCount = 0;
2642 constexpr int kMaxGlyphCount = 1 << 21;
2643 SkTextBlob::Iter i(*blob);
2644 SkTextBlob::Iter::Run r;
2645 while (i.next(&r)) {
2646 int glyphsLeft = kMaxGlyphCount - totalGlyphCount;
2647 RETURN_ON_FALSE(r.fGlyphCount <= glyphsLeft);
2648 totalGlyphCount += r.fGlyphCount;
2649 }
2650 this->onDrawTextBlob(blob, x, y, paint);
2651}
2652
2653void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2654 const SkPaint& paint) {
2655 DRAW_BEGIN(paint, nullptr)
2656
2657 while (iter.next()) {
2658 // In the common case of one iteration we could std::move vertices here.
2659 iter.fDevice->drawVertices(vertices, bmode, draw.paint());
2660 }
2661
2662 DRAW_END
2663}
2664
2665void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2666 const SkPoint texCoords[4], SkBlendMode bmode,
2667 const SkPaint& paint) {
2668 TRACE_EVENT0("skia", TRACE_FUNC);
2669 if (nullptr == cubics) {
2670 return;
2671 }
2672
2673 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
2674}
2675
2676void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2677 const SkPoint texCoords[4], SkBlendMode bmode,
2678 const SkPaint& paint) {
2679 // Since a patch is always within the convex hull of the control points, we discard it when its
2680 // bounding rectangle is completely outside the current clip.
2681 SkRect bounds;
2682 bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts);
2683 if (this->quickReject(bounds)) {
2684 return;
2685 }
2686
2687 DRAW_BEGIN(paint, nullptr)
2688
2689 while (iter.next()) {
2690 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
2691 }
2692
2693 DRAW_END
2694}
2695
2696void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2697#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2698 TRACE_EVENT0("skia", TRACE_FUNC);
2699#endif
2700 RETURN_ON_NULL(dr);
2701 if (x || y) {
2702 SkMatrix matrix = SkMatrix::Translate(x, y);
2703 this->onDrawDrawable(dr, &matrix);
2704 } else {
2705 this->onDrawDrawable(dr, nullptr);
2706 }
2707}
2708
2709void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2710#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2711 TRACE_EVENT0("skia", TRACE_FUNC);
2712#endif
2713 RETURN_ON_NULL(dr);
2714 if (matrix && matrix->isIdentity()) {
2715 matrix = nullptr;
2716 }
2717 this->onDrawDrawable(dr, matrix);
2718}
2719
2720void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2721 // drawable bounds are no longer reliable (e.g. android displaylist)
2722 // so don't use them for quick-reject
2723 this->getDevice()->drawDrawable(dr, matrix, this);
2724}
2725
2726void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2727 const SkColor colors[], int count, SkBlendMode bmode,
2728 const SkRect* cull, const SkPaint* paint) {
2729 if (cull && this->quickReject(*cull)) {
2730 return;
2731 }
2732
2733 SkPaint pnt;
2734 if (paint) {
2735 pnt = *paint;
2736 }
2737
2738 DRAW_BEGIN(pnt, nullptr)
2739 while (iter.next()) {
2740 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
2741 }
2742 DRAW_END
2743}
2744
2745void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2746 SkASSERT(key);
2747
2748 SkPaint paint;
2749 DRAW_BEGIN(paint, nullptr)
2750 while (iter.next()) {
2751 iter.fDevice->drawAnnotation(rect, key, value);
2752 }
2753 DRAW_END
2754}
2755
2756void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2757 const SkColor4f& color, SkBlendMode mode) {
2758 SkASSERT(r.isSorted());
2759
2760 // If this used a paint, it would be a filled color with blend mode, which does not
2761 // need to use an autodraw loop, so use SkDrawIter directly.
2762 if (this->quickReject(r)) {
2763 return;
2764 }
2765
2766 this->predrawNotify(&r, nullptr, false);
2767 SkDrawIter iter(this);
2768 while(iter.next()) {
2769 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2770 }
2771}
2772
2773void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2774 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2775 const SkPaint* paint, SrcRectConstraint constraint) {
2776 if (count <= 0) {
2777 // Nothing to draw
2778 return;
2779 }
2780
2781 SkPaint realPaint;
2782 init_image_paint(&realPaint, paint);
2783
2784 // We could calculate the set's dstRect union to always check quickReject(), but we can't reject
2785 // individual entries and Chromium's occlusion culling already makes it likely that at least one
2786 // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1),
2787 // or we need it for the autolooper (since it greatly improves image filter perf).
2788 bool needsAutoLooper = needs_autodrawlooper(this, realPaint);
2789 bool setBoundsValid = count == 1 || needsAutoLooper;
2790 SkRect setBounds = imageSet[0].fDstRect;
2791 if (imageSet[0].fMatrixIndex >= 0) {
2792 // Account for the per-entry transform that is applied prior to the CTM when drawing
2793 preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds);
2794 }
2795 if (needsAutoLooper) {
2796 for (int i = 1; i < count; ++i) {
2797 SkRect entryBounds = imageSet[i].fDstRect;
2798 if (imageSet[i].fMatrixIndex >= 0) {
2799 preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds);
2800 }
2801 setBounds.joinPossiblyEmptyRect(entryBounds);
2802 }
2803 }
2804
2805 // If we happen to have the draw bounds, though, might as well check quickReject().
2806 if (setBoundsValid && realPaint.canComputeFastBounds()) {
2807 SkRect tmp;
2808 if (this->quickReject(realPaint.computeFastBounds(setBounds, &tmp))) {
2809 return;
2810 }
2811 }
2812
2813 if (needsAutoLooper) {
2814 SkASSERT(setBoundsValid);
2815 DRAW_BEGIN(realPaint, &setBounds)
2816 while (iter.next()) {
2817 iter.fDevice->drawEdgeAAImageSet(
2818 imageSet, count, dstClips, preViewMatrices, draw.paint(), constraint);
2819 }
2820 DRAW_END
2821 } else {
2822 this->predrawNotify();
2823 SkDrawIter iter(this);
2824 while(iter.next()) {
2825 iter.fDevice->drawEdgeAAImageSet(
2826 imageSet, count, dstClips, preViewMatrices, realPaint, constraint);
2827 }
2828 }
2829}
2830
2831//////////////////////////////////////////////////////////////////////////////
2832// These methods are NOT virtual, and therefore must call back into virtual
2833// methods, rather than actually drawing themselves.
2834//////////////////////////////////////////////////////////////////////////////
2835
2836void SkCanvas::drawColor(const SkColor4f& c, SkBlendMode mode) {
2837 SkPaint paint;
2838 paint.setColor(c);
2839 paint.setBlendMode(mode);
2840 this->drawPaint(paint);
2841}
2842
2843void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2844 const SkPoint pt = { x, y };
2845 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2846}
2847
2848void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
2849 SkPoint pts[2];
2850 pts[0].set(x0, y0);
2851 pts[1].set(x1, y1);
2852 this->drawPoints(kLines_PointMode, 2, pts, paint);
2853}
2854
2855void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
2856 if (radius < 0) {
2857 radius = 0;
2858 }
2859
2860 SkRect r;
2861 r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
2862 this->drawOval(r, paint);
2863}
2864
2865void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2866 const SkPaint& paint) {
2867 if (rx > 0 && ry > 0) {
2868 SkRRect rrect;
2869 rrect.setRectXY(r, rx, ry);
2870 this->drawRRect(rrect, paint);
2871 } else {
2872 this->drawRect(r, paint);
2873 }
2874}
2875
2876void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2877 SkScalar sweepAngle, bool useCenter,
2878 const SkPaint& paint) {
2879 TRACE_EVENT0("skia", TRACE_FUNC);
2880 if (oval.isEmpty() || !sweepAngle) {
2881 return;
2882 }
2883 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
2884}
2885
2886///////////////////////////////////////////////////////////////////////////////
2887#ifdef SK_DISABLE_SKPICTURE
2888void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
2889
2890
2891void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2892 const SkPaint* paint) {}
2893#else
2894/**
2895 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2896 * against the playback cost of recursing into the subpicture to get at its actual ops.
2897 *
2898 * For now we pick a conservatively small value, though measurement (and other heuristics like
2899 * the type of ops contained) may justify changing this value.
2900 */
2901#define kMaxPictureOpsToUnrollInsteadOfRef 1
2902
2903void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2904 TRACE_EVENT0("skia", TRACE_FUNC);
2905 RETURN_ON_NULL(picture);
2906
2907 if (matrix && matrix->isIdentity()) {
2908 matrix = nullptr;
2909 }
2910 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2911 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2912 picture->playback(this);
2913 } else {
2914 this->onDrawPicture(picture, matrix, paint);
2915 }
2916}
2917
2918void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2919 const SkPaint* paint) {
2920 if (!paint || paint->canComputeFastBounds()) {
2921 SkRect bounds = picture->cullRect();
2922 if (paint) {
2923 paint->computeFastBounds(bounds, &bounds);
2924 }
2925 if (matrix) {
2926 matrix->mapRect(&bounds);
2927 }
2928 if (this->quickReject(bounds)) {
2929 return;
2930 }
2931 }
2932
2933 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2934 picture->playback(this);
2935}
2936#endif
2937
2938///////////////////////////////////////////////////////////////////////////////
2939///////////////////////////////////////////////////////////////////////////////
2940
2941SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
2942 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
2943
2944 SkASSERT(canvas);
2945
2946 fImpl = new (fStorage) SkDrawIter(canvas);
2947 // This advances the base iterator to the first device and caches its origin,
2948 // correctly handling the case where there are no devices.
2949 this->next();
2950}
2951
2952SkCanvas::LayerIter::~LayerIter() {
2953 fImpl->~SkDrawIter();
2954}
2955
2956void SkCanvas::LayerIter::next() {
2957 fDone = !fImpl->next();
2958 if (!fDone) {
2959 // Cache the device origin. LayerIter is only used in Android, which doesn't use image
2960 // filters, so its devices will always be able to report the origin exactly.
2961 fDeviceOrigin = fImpl->fDevice->getOrigin();
2962 }
2963}
2964
2965SkBaseDevice* SkCanvas::LayerIter::device() const {
2966 return fImpl->fDevice;
2967}
2968
2969const SkMatrix& SkCanvas::LayerIter::matrix() const {
2970 return fImpl->fDevice->localToDevice();
2971}
2972
2973const SkPaint& SkCanvas::LayerIter::paint() const {
2974 const SkPaint* paint = fImpl->getPaint();
2975 if (nullptr == paint) {
2976 paint = &fDefaultPaint;
2977 }
2978 return *paint;
2979}
2980
2981SkIRect SkCanvas::LayerIter::clipBounds() const {
2982 return fImpl->fDevice->getGlobalBounds();
2983}
2984
2985int SkCanvas::LayerIter::x() const { return fDeviceOrigin.fX; }
2986int SkCanvas::LayerIter::y() const { return fDeviceOrigin.fY; }
2987
2988///////////////////////////////////////////////////////////////////////////////
2989
2990SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2991SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2992SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2993SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2994
2995SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2996 const SkRect& dstRect, int matrixIndex, float alpha,
2997 unsigned aaFlags, bool hasClip)
2998 : fImage(std::move(image))
2999 , fSrcRect(srcRect)
3000 , fDstRect(dstRect)
3001 , fMatrixIndex(matrixIndex)
3002 , fAlpha(alpha)
3003 , fAAFlags(aaFlags)
3004 , fHasClip(hasClip) {}
3005
3006SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
3007 const SkRect& dstRect, float alpha, unsigned aaFlags)
3008 : fImage(std::move(image))
3009 , fSrcRect(srcRect)
3010 , fDstRect(dstRect)
3011 , fAlpha(alpha)
3012 , fAAFlags(aaFlags) {}
3013
3014///////////////////////////////////////////////////////////////////////////////
3015
3016std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3017 size_t rowBytes, const SkSurfaceProps* props) {
3018 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
3019 return nullptr;
3020 }
3021
3022 SkBitmap bitmap;
3023 if (!bitmap.installPixels(info, pixels, rowBytes)) {
3024 return nullptr;
3025 }
3026
3027 return props ?
3028 std::make_unique<SkCanvas>(bitmap, *props) :
3029 std::make_unique<SkCanvas>(bitmap);
3030}
3031
3032///////////////////////////////////////////////////////////////////////////////
3033
3034SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3035 : INHERITED(SkIRect::MakeWH(width, height)) {}
3036
3037SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3038 : INHERITED(bounds) {}
3039
3040SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
3041 : INHERITED(device) {}
3042
3043SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3044 (void)this->INHERITED::getSaveLayerStrategy(rec);
3045 return kNoLayer_SaveLayerStrategy;
3046}
3047
3048bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
3049 return false;
3050}
3051
3052///////////////////////////////////////////////////////////////////////////////
3053
3054static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3055static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3056static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3057static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3058static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3059static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
3060
3061///////////////////////////////////////////////////////////////////////////////////////////////////
3062
3063SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3064 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3065 const auto& dev = fMCRec->fTopLayer->fDevice;
3066 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3067 SkIRect clip = dev->devClipBounds();
3068 if (!clip.intersect({0, 0, dev->width(), dev->height()})) {
3069 clip.setEmpty();
3070 }
3071
3072 fAllocator->updateHandle(handle, dev->localToDevice(), clip);
3073 return handle;
3074 }
3075 return nullptr;
3076}
3077
3078static bool install(SkBitmap* bm, const SkImageInfo& info,
3079 const SkRasterHandleAllocator::Rec& rec) {
3080 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
3081}
3082
3083SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3084 SkBitmap* bm) {
3085 SkRasterHandleAllocator::Rec rec;
3086 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3087 return nullptr;
3088 }
3089 return rec.fHandle;
3090}
3091
3092std::unique_ptr<SkCanvas>
3093SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3094 const SkImageInfo& info, const Rec* rec) {
3095 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
3096 return nullptr;
3097 }
3098
3099 SkBitmap bm;
3100 Handle hndl;
3101
3102 if (rec) {
3103 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3104 } else {
3105 hndl = alloc->allocBitmap(info, &bm);
3106 }
3107 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3108}
3109
3110///////////////////////////////////////////////////////////////////////////////////////////////////
3111