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