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 // The local bounds of the src device; all the bounds passed to snapSpecial must be intersected
889 // with this rect.
890 const SkIRect srcDevRect = SkIRect::MakeWH(src->width(), src->height());
891
892 if (!filter) {
893 // All non-filtered devices are currently axis aligned, so they only differ by their origin.
894 // This means that we only have to copy a dst-sized block of pixels out of src and translate
895 // it to the matching position relative to dst's origin.
896 SkIRect snapBounds = SkIRect::MakeXYWH(dstOrigin.x() - src->getOrigin().x(),
897 dstOrigin.y() - src->getOrigin().y(),
898 dst->width(), dst->height());
899 if (!snapBounds.intersect(srcDevRect)) {
900 return;
901 }
902
903 auto special = src->snapSpecial(snapBounds);
904 if (special) {
905 // The image is drawn at 1-1 scale with integer translation, so no filtering is needed.
906 SkPaint p;
907 dst->drawSpecial(special.get(), 0, 0, p, nullptr, SkMatrix::I());
908 }
909 return;
910 }
911
912 // First decompose the ctm into a post-filter transform and a filter matrix that is supported
913 // by the backdrop filter.
914 SkMatrix toRoot, layerMatrix;
915 SkSize scale;
916 if (ctm.isScaleTranslate() || as_IFB(filter)->canHandleComplexCTM()) {
917 toRoot = SkMatrix::I();
918 layerMatrix = ctm;
919 } else if (ctm.decomposeScale(&scale, &toRoot)) {
920 layerMatrix = SkMatrix::MakeScale(scale.fWidth, scale.fHeight);
921 } else {
922 // Perspective, for now, do no scaling of the layer itself.
923 // TODO (michaelludwig) - perhaps it'd be better to explore a heuristic scale pulled from
924 // the matrix, e.g. based on the midpoint of the near/far planes?
925 toRoot = ctm;
926 layerMatrix = SkMatrix::I();
927 }
928
929 // We have to map the dst bounds from the root space into the layer space where filtering will
930 // occur. If we knew the input bounds of the content that defined the original dst bounds, we
931 // could map that forward by layerMatrix and have tighter bounds, but toRoot^-1 * dst bounds
932 // is a safe, conservative estimate.
933 SkMatrix fromRoot;
934 if (!toRoot.invert(&fromRoot)) {
935 return;
936 }
937
938 // This represents what the backdrop filter needs to produce in the layer space, and is sized
939 // such that drawing it into dst with the toRoot transform will cover the actual dst device.
940 SkIRect layerTargetBounds = fromRoot.mapRect(
941 SkRect::MakeXYWH(dstOrigin.x(), dstOrigin.y(), dst->width(), dst->height())).roundOut();
942 // While layerTargetBounds is what needs to be output by the filter, the filtering process may
943 // require some extra input pixels.
944 SkIRect layerInputBounds = filter->filterBounds(
945 layerTargetBounds, layerMatrix, SkImageFilter::kReverse_MapDirection,
946 &layerTargetBounds);
947
948 // Map the required input into the root space, then make relative to the src device. This will
949 // be the conservative contents required to fill a layerInputBounds-sized surface with the
950 // backdrop content (transformed back into the layer space using fromRoot).
951 SkIRect backdropBounds = toRoot.mapRect(SkRect::Make(layerInputBounds)).roundOut();
952 backdropBounds.offset(-src->getOrigin().x(), -src->getOrigin().y());
953 if (!backdropBounds.intersect(srcDevRect)) {
954 return;
955 }
956
957 auto special = src->snapSpecial(backdropBounds);
958 if (!special) {
959 return;
960 }
961
962 SkColorType colorType = src->imageInfo().colorType();
963 if (colorType == kUnknown_SkColorType) {
964 colorType = kRGBA_8888_SkColorType;
965 }
966 SkColorSpace* colorSpace = src->imageInfo().colorSpace();
967
968 SkPaint p;
969 if (!toRoot.isIdentity()) {
970 // Drawing the temporary and final filtered image requires a higher filter quality if the
971 // 'toRoot' transformation is not identity, in order to minimize the impact on already
972 // rendered edges/content.
973 // TODO (michaelludwig) - Explore reducing this quality, identify visual tradeoffs
974 p.setFilterQuality(kHigh_SkFilterQuality);
975
976 // The snapped backdrop content needs to be transformed by fromRoot into the layer space,
977 // and stored in a temporary surface, which is then used as the input to the actual filter.
978 auto tmpSurface = special->makeSurface(colorType, colorSpace, layerInputBounds.size());
979 if (!tmpSurface) {
980 return;
981 }
982
983 auto tmpCanvas = tmpSurface->getCanvas();
984 tmpCanvas->clear(SK_ColorTRANSPARENT);
985 // Reading in reverse, this takes the backdrop bounds from src device space into the root
986 // space, then maps from root space into the layer space, then maps it so the input layer's
987 // top left corner is (0, 0). This transformation automatically accounts for any cropping
988 // performed on backdropBounds.
989 tmpCanvas->translate(-layerInputBounds.fLeft, -layerInputBounds.fTop);
990 tmpCanvas->concat(fromRoot);
991 tmpCanvas->translate(src->getOrigin().x(), src->getOrigin().y());
992
993 tmpCanvas->drawImageRect(special->asImage(), special->subset(),
994 SkRect::Make(backdropBounds), &p, kStrict_SrcRectConstraint);
995 special = tmpSurface->makeImageSnapshot();
996 } else {
997 // Since there is no extra transform that was done, update the input bounds to reflect
998 // cropping of the snapped backdrop image. In this case toRoot = I, so layerInputBounds
999 // was equal to backdropBounds before it was made relative to the src device and cropped.
1000 // When we use the original snapped image directly, just map the update backdrop bounds
1001 // back into the shared layer space
1002 layerInputBounds = backdropBounds;
1003 layerInputBounds.offset(src->getOrigin().x(), src->getOrigin().y());
1004
1005 // Similar to the unfiltered case above, when toRoot is the identity, then the final
1006 // draw will be 1-1 so there is no need to increase filter quality.
1007 p.setFilterQuality(kNone_SkFilterQuality);
1008 }
1009
1010 // Now evaluate the filter on 'special', which contains the backdrop content mapped back into
1011 // layer space. This has to further offset everything so that filter evaluation thinks the
1012 // source image's top left corner is (0, 0).
1013 // TODO (michaelludwig) - Once image filters are robust to non-(0,0) image origins for inputs,
1014 // this can be simplified.
1015 layerTargetBounds.offset(-layerInputBounds.fLeft, -layerInputBounds.fTop);
1016 SkMatrix filterCTM = layerMatrix;
1017 filterCTM.postTranslate(-layerInputBounds.fLeft, -layerInputBounds.fTop);
1018 skif::Context ctx(filterCTM, layerTargetBounds, nullptr, colorType, colorSpace, special.get());
1019
1020 SkIPoint offset;
1021 special = as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset);
1022 if (special) {
1023 // Draw the filtered backdrop content into the dst device. We add layerInputBounds origin
1024 // to offset because the original value in 'offset' was relative to 'filterCTM'. 'filterCTM'
1025 // had subtracted the layerInputBounds origin, so adding that back makes 'offset' relative
1026 // to 'layerMatrix' (what we need it to be when drawing the image by 'toRoot').
1027 offset += layerInputBounds.topLeft();
1028
1029 // Manually setting the device's CTM requires accounting for the device's origin.
1030 // TODO (michaelludwig) - This could be simpler if the dst device had its origin configured
1031 // before filtering the backdrop device, and if SkAutoDeviceCTMRestore had a way to accept
1032 // a global CTM instead of a device CTM.
1033 SkMatrix dstCTM = toRoot;
1034 dstCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
1035 SkAutoDeviceCTMRestore acr(dst, dstCTM);
1036
1037 // And because devices don't have a special-image draw function that supports arbitrary
1038 // matrices, we are abusing the asImage() functionality here...
1039 SkRect specialSrc = SkRect::Make(special->subset());
1040 auto looseImage = special->asImage();
1041 dst->drawImageRect(
1042 looseImage.get(), &specialSrc,
1043 SkRect::MakeXYWH(offset.x(), offset.y(), special->width(), special->height()),
1044 p, kStrict_SrcRectConstraint);
1045 }
1046 }
1047
make_layer_info(const SkImageInfo & prev,int w,int h,const SkPaint * paint)1048 static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
1049 SkColorType ct = prev.colorType();
1050 if (prev.bytesPerPixel() <= 4 &&
1051 prev.colorType() != kRGBA_8888_SkColorType &&
1052 prev.colorType() != kBGRA_8888_SkColorType) {
1053 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
1054 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
1055 ct = kN32_SkColorType;
1056 }
1057 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
1058 }
1059
internalSaveLayer(const SaveLayerRec & rec,SaveLayerStrategy strategy)1060 void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1061 TRACE_EVENT0("skia", TRACE_FUNC);
1062 const SkRect* bounds = rec.fBounds;
1063 const SkPaint* paint = rec.fPaint;
1064 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1065
1066 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
1067 // regardless of any hint-rect from the caller. skbug.com/8783
1068 if (rec.fBackdrop) {
1069 bounds = nullptr;
1070 }
1071
1072 SkLazyPaint lazyP;
1073 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
1074 SkMatrix stashedMatrix = fMCRec->fMatrix;
1075 MCRec* modifiedRec = nullptr;
1076
1077 /*
1078 * Many ImageFilters (so far) do not (on their own) correctly handle matrices (CTM) that
1079 * contain rotation/skew/etc. We rely on applyCTM to create a new image filter DAG as needed to
1080 * accommodate this, but it requires update the CTM we use when drawing into the layer.
1081 *
1082 * 1. Stash off the current CTM
1083 * 2. Apply the CTM to imagefilter, which decomposes it into simple and complex transforms
1084 * if necessary.
1085 * 3. Wack the CTM to be the remaining scale matrix and use the modified imagefilter, which
1086 * is a MatrixImageFilter that contains the complex matrix.
1087 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1088 * 5. During restore, the MatrixImageFilter automatically applies complex stage to the output
1089 * of the original imagefilter, and draw that (via drawSprite)
1090 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1091 *
1092 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1093 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1094 */
1095 if (imageFilter) {
1096 SkMatrix modifiedCTM;
1097 sk_sp<SkImageFilter> modifiedFilter = as_IFB(imageFilter)->applyCTM(stashedMatrix,
1098 &modifiedCTM);
1099 if (as_IFB(modifiedFilter)->uniqueID() != as_IFB(imageFilter)->uniqueID()) {
1100 // The original filter couldn't support the CTM entirely
1101 SkASSERT(modifiedCTM.isScaleTranslate() || as_IFB(imageFilter)->canHandleComplexCTM());
1102 modifiedRec = fMCRec;
1103 this->internalSetMatrix(modifiedCTM);
1104 SkPaint* p = lazyP.set(*paint);
1105 p->setImageFilter(std::move(modifiedFilter));
1106 imageFilter = p->getImageFilter();
1107 paint = p;
1108 }
1109 // Else the filter didn't change, so modifiedCTM == stashedMatrix and there's nothing
1110 // left to do since the stack already has that as the CTM.
1111 }
1112
1113 // do this before we create the layer. We don't call the public save() since
1114 // that would invoke a possibly overridden virtual
1115 this->internalSave();
1116
1117 SkIRect ir;
1118 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
1119 if (modifiedRec) {
1120 // In this case there will be no layer in which to stash the matrix so we need to
1121 // revert the prior MCRec to its earlier state.
1122 modifiedRec->fMatrix = stashedMatrix;
1123 }
1124 return;
1125 }
1126
1127 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1128 // the clipRectBounds() call above?
1129 if (kNoLayer_SaveLayerStrategy == strategy) {
1130 return;
1131 }
1132
1133 SkPixelGeometry geo = fProps.pixelGeometry();
1134 if (paint) {
1135 // TODO: perhaps add a query to filters so we might preserve opaqueness...
1136 if (paint->getImageFilter() || paint->getColorFilter()) {
1137 geo = kUnknown_SkPixelGeometry;
1138 }
1139 }
1140
1141 SkBaseDevice* priorDevice = this->getTopDevice();
1142 if (nullptr == priorDevice) { // Do we still need this check???
1143 SkDebugf("Unable to find device for layer.");
1144 return;
1145 }
1146
1147 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
1148 if (rec.fSaveLayerFlags & kF16ColorType) {
1149 info = info.makeColorType(kRGBA_F16_SkColorType);
1150 }
1151
1152 sk_sp<SkBaseDevice> newDevice;
1153 {
1154 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
1155 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
1156 const SkBaseDevice::TileUsage usage =
1157 preserveLCDText ? SkBaseDevice::kPossible_TileUsage : SkBaseDevice::kNever_TileUsage;
1158 const bool trackCoverage =
1159 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
1160 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1161 trackCoverage,
1162 fAllocator.get());
1163 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1164 if (!newDevice) {
1165 return;
1166 }
1167 }
1168 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
1169
1170 // only have a "next" if this new layer doesn't affect the clip (rare)
1171 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
1172 fMCRec->fLayer = layer;
1173 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
1174
1175 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
1176 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
1177 fMCRec->fMatrix);
1178 }
1179
1180 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1181
1182 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1183 if (layer->fNext) {
1184 // need to punch a hole in the previous device, so we don't draw there, given that
1185 // the new top-layer will allow drawing to happen "below" it.
1186 SkRegion hole(ir);
1187 do {
1188 layer = layer->fNext;
1189 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1190 } while (layer->fNext);
1191 }
1192 }
1193
saveLayerAlpha(const SkRect * bounds,U8CPU alpha)1194 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1195 if (0xFF == alpha) {
1196 return this->saveLayer(bounds, nullptr);
1197 } else {
1198 SkPaint tmpPaint;
1199 tmpPaint.setAlpha(alpha);
1200 return this->saveLayer(bounds, &tmpPaint);
1201 }
1202 }
1203
internalSaveBehind(const SkRect * localBounds)1204 void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1205 SkIRect devBounds;
1206 if (localBounds) {
1207 SkRect tmp;
1208 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1209 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1210 devBounds.setEmpty();
1211 }
1212 } else {
1213 devBounds = this->getDeviceClipBounds();
1214 }
1215 if (devBounds.isEmpty()) {
1216 return;
1217 }
1218
1219 SkBaseDevice* device = this->getTopDevice();
1220 if (nullptr == device) { // Do we still need this check???
1221 return;
1222 }
1223
1224 // need the bounds relative to the device itself
1225 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1226
1227 // This is getting the special image from the current device, which is then drawn into (both by
1228 // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its
1229 // own device, we need to explicitly copy the back image contents so that its original content
1230 // is available when we splat it back later during restore.
1231 auto backImage = device->snapSpecial(devBounds, /* copy */ true);
1232 if (!backImage) {
1233 return;
1234 }
1235
1236 // we really need the save, so we can wack the fMCRec
1237 this->checkForDeferredSave();
1238
1239 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1240
1241 SkPaint paint;
1242 paint.setBlendMode(SkBlendMode::kClear);
1243 this->drawClippedToSaveBehind(paint);
1244 }
1245
internalRestore()1246 void SkCanvas::internalRestore() {
1247 SkASSERT(fMCStack.count() != 0);
1248
1249 // reserve our layer (if any)
1250 DeviceCM* layer = fMCRec->fLayer; // may be null
1251 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1252 fMCRec->fLayer = nullptr;
1253
1254 // move this out before we do the actual restore
1255 auto backImage = std::move(fMCRec->fBackImage);
1256
1257 // now do the normal restore()
1258 fMCRec->~MCRec(); // balanced in save()
1259 fMCStack.pop_back();
1260 fMCRec = (MCRec*)fMCStack.back();
1261
1262 if (fMCRec) {
1263 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1264 }
1265
1266 if (backImage) {
1267 SkPaint paint;
1268 paint.setBlendMode(SkBlendMode::kDstOver);
1269 const int x = backImage->fLoc.x();
1270 const int y = backImage->fLoc.y();
1271 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1272 nullptr, SkMatrix::I());
1273 }
1274
1275 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1276 since if we're being recorded, we don't want to record this (the
1277 recorder will have already recorded the restore).
1278 */
1279 if (layer) {
1280 if (fMCRec) {
1281 const SkIPoint& origin = layer->fDevice->getOrigin();
1282 layer->fDevice->setImmutable();
1283 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
1284 layer->fPaint.get(),
1285 layer->fClipImage.get(), layer->fClipMatrix);
1286 // restore what we smashed in internalSaveLayer
1287 this->internalSetMatrix(layer->fStashedMatrix);
1288 // reset this, since internalDrawDevice will have set it to true
1289 delete layer;
1290 } else {
1291 // we're at the root
1292 SkASSERT(layer == (void*)fDeviceCMStorage);
1293 layer->~DeviceCM();
1294 // no need to update fMCRec, 'cause we're killing the canvas
1295 }
1296 }
1297
1298 if (fMCRec) {
1299 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1300 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1301 }
1302 }
1303
makeSurface(const SkImageInfo & info,const SkSurfaceProps * props)1304 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1305 if (nullptr == props) {
1306 props = &fProps;
1307 }
1308 return this->onNewSurface(info, *props);
1309 }
1310
onNewSurface(const SkImageInfo & info,const SkSurfaceProps & props)1311 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1312 SkBaseDevice* dev = this->getDevice();
1313 return dev ? dev->makeSurface(info, props) : nullptr;
1314 }
1315
imageInfo() const1316 SkImageInfo SkCanvas::imageInfo() const {
1317 return this->onImageInfo();
1318 }
1319
onImageInfo() const1320 SkImageInfo SkCanvas::onImageInfo() const {
1321 SkBaseDevice* dev = this->getDevice();
1322 if (dev) {
1323 return dev->imageInfo();
1324 } else {
1325 return SkImageInfo::MakeUnknown(0, 0);
1326 }
1327 }
1328
getProps(SkSurfaceProps * props) const1329 bool SkCanvas::getProps(SkSurfaceProps* props) const {
1330 return this->onGetProps(props);
1331 }
1332
onGetProps(SkSurfaceProps * props) const1333 bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
1334 SkBaseDevice* dev = this->getDevice();
1335 if (dev) {
1336 if (props) {
1337 *props = fProps;
1338 }
1339 return true;
1340 } else {
1341 return false;
1342 }
1343 }
1344
peekPixels(SkPixmap * pmap)1345 bool SkCanvas::peekPixels(SkPixmap* pmap) {
1346 return this->onPeekPixels(pmap);
1347 }
1348
onPeekPixels(SkPixmap * pmap)1349 bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
1350 SkBaseDevice* dev = this->getDevice();
1351 return dev && dev->peekPixels(pmap);
1352 }
1353
accessTopLayerPixels(SkImageInfo * info,size_t * rowBytes,SkIPoint * origin)1354 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1355 SkPixmap pmap;
1356 if (!this->onAccessTopLayerPixels(&pmap)) {
1357 return nullptr;
1358 }
1359 if (info) {
1360 *info = pmap.info();
1361 }
1362 if (rowBytes) {
1363 *rowBytes = pmap.rowBytes();
1364 }
1365 if (origin) {
1366 *origin = this->getTopDevice()->getOrigin();
1367 }
1368 return pmap.writable_addr();
1369 }
1370
onAccessTopLayerPixels(SkPixmap * pmap)1371 bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
1372 SkBaseDevice* dev = this->getTopDevice();
1373 return dev && dev->accessPixels(pmap);
1374 }
1375
1376 /////////////////////////////////////////////////////////////////////////////
1377
1378 // In our current design/features, we should never have a layer (src) in a different colorspace
1379 // than its parent (dst), so we assert that here. This is called out from other asserts, in case
1380 // we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1381 // colorspace.
check_drawdevice_colorspaces(SkColorSpace * src,SkColorSpace * dst)1382 static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1383 SkASSERT(src == dst);
1384 }
1385
internalDrawDevice(SkBaseDevice * srcDev,int x,int y,const SkPaint * paint,SkImage * clipImage,const SkMatrix & clipMatrix)1386 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1387 SkImage* clipImage, const SkMatrix& clipMatrix) {
1388 SkPaint tmp;
1389 if (nullptr == paint) {
1390 paint = &tmp;
1391 }
1392
1393 DRAW_BEGIN_DRAWDEVICE(*paint)
1394
1395 while (iter.next()) {
1396 SkBaseDevice* dstDev = iter.fDevice;
1397 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1398 srcDev->imageInfo().colorSpace());
1399 paint = &draw.paint();
1400 SkImageFilter* filter = paint->getImageFilter();
1401 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1402 if (filter || clipImage) {
1403 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1404 if (specialImage) {
1405 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1406 specialImage->getColorSpace());
1407 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1408 clipImage, clipMatrix);
1409 }
1410 } else {
1411 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
1412 }
1413 }
1414
1415 DRAW_END
1416 }
1417
1418 /////////////////////////////////////////////////////////////////////////////
1419
translate(SkScalar dx,SkScalar dy)1420 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1421 if (dx || dy) {
1422 this->checkForDeferredSave();
1423 fMCRec->fMatrix.preTranslate(dx,dy);
1424
1425 // Translate shouldn't affect the is-scale-translateness of the matrix.
1426 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
1427
1428 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1429
1430 this->didTranslate(dx,dy);
1431 }
1432 }
1433
scale(SkScalar sx,SkScalar sy)1434 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1435 SkMatrix m;
1436 m.setScale(sx, sy);
1437 this->concat(m);
1438 }
1439
rotate(SkScalar degrees)1440 void SkCanvas::rotate(SkScalar degrees) {
1441 SkMatrix m;
1442 m.setRotate(degrees);
1443 this->concat(m);
1444 }
1445
rotate(SkScalar degrees,SkScalar px,SkScalar py)1446 void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1447 SkMatrix m;
1448 m.setRotate(degrees, px, py);
1449 this->concat(m);
1450 }
1451
skew(SkScalar sx,SkScalar sy)1452 void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1453 SkMatrix m;
1454 m.setSkew(sx, sy);
1455 this->concat(m);
1456 }
1457
concat(const SkMatrix & matrix)1458 void SkCanvas::concat(const SkMatrix& matrix) {
1459 if (matrix.isIdentity()) {
1460 return;
1461 }
1462
1463 this->checkForDeferredSave();
1464 fMCRec->fMatrix.preConcat(matrix);
1465 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1466
1467 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1468
1469 this->didConcat(matrix);
1470 }
1471
internalSetMatrix(const SkMatrix & matrix)1472 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
1473 fMCRec->fMatrix = matrix;
1474 fIsScaleTranslate = matrix.isScaleTranslate();
1475
1476 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1477 }
1478
setMatrix(const SkMatrix & matrix)1479 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1480 this->checkForDeferredSave();
1481 this->internalSetMatrix(matrix);
1482 this->didSetMatrix(matrix);
1483 }
1484
resetMatrix()1485 void SkCanvas::resetMatrix() {
1486 this->setMatrix(SkMatrix::I());
1487 }
1488
1489 //////////////////////////////////////////////////////////////////////////////
1490
clipRect(const SkRect & rect,SkClipOp op,bool doAA)1491 void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
1492 if (!rect.isFinite()) {
1493 return;
1494 }
1495 this->checkForDeferredSave();
1496 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1497 this->onClipRect(rect, op, edgeStyle);
1498 }
1499
onClipRect(const SkRect & rect,SkClipOp op,ClipEdgeStyle edgeStyle)1500 void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1501 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1502
1503 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
1504
1505 AutoValidateClip avc(this);
1506 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1507 isAA);
1508 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1509 }
1510
androidFramework_setDeviceClipRestriction(const SkIRect & rect)1511 void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1512 fClipRestrictionRect = rect;
1513 if (fClipRestrictionRect.isEmpty()) {
1514 // we notify the device, but we *dont* resolve deferred saves (since we're just
1515 // removing the restriction if the rect is empty. how I hate this api.
1516 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1517 } else {
1518 this->checkForDeferredSave();
1519 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1520 AutoValidateClip avc(this);
1521 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
1522 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1523 }
1524 }
1525
clipRRect(const SkRRect & rrect,SkClipOp op,bool doAA)1526 void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
1527 this->checkForDeferredSave();
1528 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1529 if (rrect.isRect()) {
1530 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1531 } else {
1532 this->onClipRRect(rrect, op, edgeStyle);
1533 }
1534 }
1535
onClipRRect(const SkRRect & rrect,SkClipOp op,ClipEdgeStyle edgeStyle)1536 void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1537 AutoValidateClip avc(this);
1538
1539 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1540
1541 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
1542
1543 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1544 isAA);
1545 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1546 }
1547
clipPath(const SkPath & path,SkClipOp op,bool doAA)1548 void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
1549 this->checkForDeferredSave();
1550 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1551
1552 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1553 SkRect r;
1554 if (path.isRect(&r)) {
1555 this->onClipRect(r, op, edgeStyle);
1556 return;
1557 }
1558 SkRRect rrect;
1559 if (path.isOval(&r)) {
1560 rrect.setOval(r);
1561 this->onClipRRect(rrect, op, edgeStyle);
1562 return;
1563 }
1564 if (path.isRRect(&rrect)) {
1565 this->onClipRRect(rrect, op, edgeStyle);
1566 return;
1567 }
1568 }
1569
1570 this->onClipPath(path, op, edgeStyle);
1571 }
1572
onClipPath(const SkPath & path,SkClipOp op,ClipEdgeStyle edgeStyle)1573 void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
1574 AutoValidateClip avc(this);
1575
1576 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1577
1578 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
1579
1580 const SkPath* rasterClipPath = &path;
1581 const SkMatrix* matrix = &fMCRec->fMatrix;
1582 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1583 (SkRegion::Op)op, isAA);
1584 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1585 }
1586
clipRegion(const SkRegion & rgn,SkClipOp op)1587 void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
1588 this->checkForDeferredSave();
1589 this->onClipRegion(rgn, op);
1590 }
1591
onClipRegion(const SkRegion & rgn,SkClipOp op)1592 void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
1593 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
1594
1595 AutoValidateClip avc(this);
1596
1597 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
1598 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1599 }
1600
1601 #ifdef SK_DEBUG
validateClip() const1602 void SkCanvas::validateClip() const {
1603 #ifndef SK_DISABLE_SLOW_DEBUG_VALIDATION
1604 // construct clipRgn from the clipstack
1605 const SkBaseDevice* device = this->getDevice();
1606 if (!device) {
1607 SkASSERT(this->isClipEmpty());
1608 return;
1609 }
1610 #endif
1611 }
1612 #endif
1613
androidFramework_isClipAA() const1614 bool SkCanvas::androidFramework_isClipAA() const {
1615 bool containsAA = false;
1616
1617 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1618
1619 return containsAA;
1620 }
1621
1622 class RgnAccumulator {
1623 SkRegion* fRgn;
1624 public:
RgnAccumulator(SkRegion * total)1625 RgnAccumulator(SkRegion* total) : fRgn(total) {}
accumulate(SkBaseDevice * device,SkRegion * rgn)1626 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1627 SkIPoint origin = device->getOrigin();
1628 if (origin.x() | origin.y()) {
1629 rgn->translate(origin.x(), origin.y());
1630 }
1631 fRgn->op(*rgn, SkRegion::kUnion_Op);
1632 }
1633 };
1634
temporary_internal_getRgnClip(SkRegion * rgn)1635 void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1636 RgnAccumulator accum(rgn);
1637 SkRegion tmp;
1638
1639 rgn->setEmpty();
1640 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
1641 }
1642
1643 ///////////////////////////////////////////////////////////////////////////////
1644
isClipEmpty() const1645 bool SkCanvas::isClipEmpty() const {
1646 return fMCRec->fRasterClip.isEmpty();
1647
1648 // TODO: should we only use the conservative answer in a recording canvas?
1649 #if 0
1650 SkBaseDevice* dev = this->getTopDevice();
1651 // if no device we return true
1652 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
1653 #endif
1654 }
1655
isClipRect() const1656 bool SkCanvas::isClipRect() const {
1657 SkBaseDevice* dev = this->getTopDevice();
1658 // if no device we return false
1659 return dev && dev->onGetClipType() == SkBaseDevice::ClipType::kRect;
1660 }
1661
is_nan_or_clipped(const Sk4f & devRect,const Sk4f & devClip)1662 static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1663 #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1664 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1665 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1666 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1667 return 0xF != _mm_movemask_ps(mask);
1668 #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1669 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1670 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1671 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1672 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1673 #else
1674 SkRect devRectAsRect;
1675 SkRect devClipAsRect;
1676 devRect.store(&devRectAsRect.fLeft);
1677 devClip.store(&devClipAsRect.fLeft);
1678 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1679 #endif
1680 }
1681
1682 // It's important for this function to not be inlined. Otherwise the compiler will share code
1683 // 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)1684 static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1685 const SkMatrix& matrix) {
1686 SkRect deviceRect;
1687 matrix.mapRect(&deviceRect, src);
1688 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1689 }
1690
quickReject(const SkRect & src) const1691 bool SkCanvas::quickReject(const SkRect& src) const {
1692 #ifdef SK_DEBUG
1693 // Verify that fDeviceClipBounds are set properly.
1694 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1695 if (fMCRec->fRasterClip.isEmpty()) {
1696 SkASSERT(fDeviceClipBounds.isEmpty());
1697 } else {
1698 SkASSERT(tmp == fDeviceClipBounds);
1699 }
1700
1701 // Verify that fIsScaleTranslate is set properly.
1702 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
1703 #endif
1704
1705 if (!fIsScaleTranslate) {
1706 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1707 }
1708
1709 // We inline the implementation of mapScaleTranslate() for the fast path.
1710 float sx = fMCRec->fMatrix.getScaleX();
1711 float sy = fMCRec->fMatrix.getScaleY();
1712 float tx = fMCRec->fMatrix.getTranslateX();
1713 float ty = fMCRec->fMatrix.getTranslateY();
1714 Sk4f scale(sx, sy, sx, sy);
1715 Sk4f trans(tx, ty, tx, ty);
1716
1717 // Apply matrix.
1718 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1719
1720 // Make sure left < right, top < bottom.
1721 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1722 Sk4f min = Sk4f::Min(ltrb, rblt);
1723 Sk4f max = Sk4f::Max(ltrb, rblt);
1724 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1725 // ARM this sequence generates the fastest (a single instruction).
1726 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1727
1728 // Check if the device rect is NaN or outside the clip.
1729 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
1730 }
1731
quickReject(const SkPath & path) const1732 bool SkCanvas::quickReject(const SkPath& path) const {
1733 return path.isEmpty() || this->quickReject(path.getBounds());
1734 }
1735
getLocalClipBounds() const1736 SkRect SkCanvas::getLocalClipBounds() const {
1737 SkIRect ibounds = this->getDeviceClipBounds();
1738 if (ibounds.isEmpty()) {
1739 return SkRect::MakeEmpty();
1740 }
1741
1742 SkMatrix inverse;
1743 // if we can't invert the CTM, we can't return local clip bounds
1744 if (!fMCRec->fMatrix.invert(&inverse)) {
1745 return SkRect::MakeEmpty();
1746 }
1747
1748 SkRect bounds;
1749 // adjust it outwards in case we are antialiasing
1750 const int margin = 1;
1751
1752 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
1753 inverse.mapRect(&bounds, r);
1754 return bounds;
1755 }
1756
getDeviceClipBounds() const1757 SkIRect SkCanvas::getDeviceClipBounds() const {
1758 return fMCRec->fRasterClip.getBounds();
1759 }
1760
getTotalMatrix() const1761 const SkMatrix& SkCanvas::getTotalMatrix() const {
1762 return fMCRec->fMatrix;
1763 }
1764
internal_private_accessTopLayerRenderTargetContext()1765 GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
1766 SkBaseDevice* dev = this->getTopDevice();
1767 return dev ? dev->accessRenderTargetContext() : nullptr;
1768 }
1769
getGrContext()1770 GrContext* SkCanvas::getGrContext() {
1771 SkBaseDevice* device = this->getTopDevice();
1772 return device ? device->context() : nullptr;
1773 }
1774
drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)1775 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1776 const SkPaint& paint) {
1777 TRACE_EVENT0("skia", TRACE_FUNC);
1778 if (outer.isEmpty()) {
1779 return;
1780 }
1781 if (inner.isEmpty()) {
1782 this->drawRRect(outer, paint);
1783 return;
1784 }
1785
1786 // We don't have this method (yet), but technically this is what we should
1787 // be able to return ...
1788 // if (!outer.contains(inner))) {
1789 //
1790 // For now at least check for containment of bounds
1791 if (!outer.getBounds().contains(inner.getBounds())) {
1792 return;
1793 }
1794
1795 this->onDrawDRRect(outer, inner, paint);
1796 }
1797
drawPaint(const SkPaint & paint)1798 void SkCanvas::drawPaint(const SkPaint& paint) {
1799 TRACE_EVENT0("skia", TRACE_FUNC);
1800 this->onDrawPaint(paint);
1801 }
1802
drawRect(const SkRect & r,const SkPaint & paint)1803 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1804 TRACE_EVENT0("skia", TRACE_FUNC);
1805 // To avoid redundant logic in our culling code and various backends, we always sort rects
1806 // before passing them along.
1807 this->onDrawRect(r.makeSorted(), paint);
1808 }
1809
drawClippedToSaveBehind(const SkPaint & paint)1810 void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1811 TRACE_EVENT0("skia", TRACE_FUNC);
1812 this->onDrawBehind(paint);
1813 }
1814
drawRegion(const SkRegion & region,const SkPaint & paint)1815 void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1816 TRACE_EVENT0("skia", TRACE_FUNC);
1817 if (region.isEmpty()) {
1818 return;
1819 }
1820
1821 if (region.isRect()) {
1822 return this->drawIRect(region.getBounds(), paint);
1823 }
1824
1825 this->onDrawRegion(region, paint);
1826 }
1827
drawOval(const SkRect & r,const SkPaint & paint)1828 void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1829 TRACE_EVENT0("skia", TRACE_FUNC);
1830 // To avoid redundant logic in our culling code and various backends, we always sort rects
1831 // before passing them along.
1832 this->onDrawOval(r.makeSorted(), paint);
1833 }
1834
drawRRect(const SkRRect & rrect,const SkPaint & paint)1835 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1836 TRACE_EVENT0("skia", TRACE_FUNC);
1837 this->onDrawRRect(rrect, paint);
1838 }
1839
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1840 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1841 TRACE_EVENT0("skia", TRACE_FUNC);
1842 this->onDrawPoints(mode, count, pts, paint);
1843 }
1844
drawVertices(const sk_sp<SkVertices> & vertices,SkBlendMode mode,const SkPaint & paint)1845 void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1846 const SkPaint& paint) {
1847 TRACE_EVENT0("skia", TRACE_FUNC);
1848 RETURN_ON_NULL(vertices);
1849 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1850 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
1851 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
1852 }
1853
drawVertices(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)1854 void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1855 TRACE_EVENT0("skia", TRACE_FUNC);
1856 RETURN_ON_NULL(vertices);
1857 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1858 }
1859
drawVertices(const sk_sp<SkVertices> & vertices,const SkVertices::Bone bones[],int boneCount,SkBlendMode mode,const SkPaint & paint)1860 void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1861 int boneCount, SkBlendMode mode, const SkPaint& paint) {
1862 TRACE_EVENT0("skia", TRACE_FUNC);
1863 RETURN_ON_NULL(vertices);
1864 SkASSERT(boneCount <= 80);
1865 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1866 }
1867
drawVertices(const SkVertices * vertices,const SkVertices::Bone bones[],int boneCount,SkBlendMode mode,const SkPaint & paint)1868 void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1869 int boneCount, SkBlendMode mode, const SkPaint& paint) {
1870 TRACE_EVENT0("skia", TRACE_FUNC);
1871 RETURN_ON_NULL(vertices);
1872 SkASSERT(boneCount <= 80);
1873 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
1874 }
1875
drawPath(const SkPath & path,const SkPaint & paint)1876 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1877 TRACE_EVENT0("skia", TRACE_FUNC);
1878 this->onDrawPath(path, paint);
1879 }
1880
drawImage(const SkImage * image,SkScalar x,SkScalar y,const SkPaint * paint)1881 void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1882 TRACE_EVENT0("skia", TRACE_FUNC);
1883 RETURN_ON_NULL(image);
1884 this->onDrawImage(image, x, y, paint);
1885 }
1886
1887 // Returns true if the rect can be "filled" : non-empty and finite
fillable(const SkRect & r)1888 static bool fillable(const SkRect& r) {
1889 SkScalar w = r.width();
1890 SkScalar h = r.height();
1891 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1892 }
1893
drawImageRect(const SkImage * image,const SkRect & src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1894 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1895 const SkPaint* paint, SrcRectConstraint constraint) {
1896 TRACE_EVENT0("skia", TRACE_FUNC);
1897 RETURN_ON_NULL(image);
1898 if (!fillable(dst) || !fillable(src)) {
1899 return;
1900 }
1901 this->onDrawImageRect(image, &src, dst, paint, constraint);
1902 }
1903
drawImageRect(const SkImage * image,const SkIRect & isrc,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1904 void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1905 const SkPaint* paint, SrcRectConstraint constraint) {
1906 RETURN_ON_NULL(image);
1907 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
1908 }
1909
drawImageRect(const SkImage * image,const SkRect & dst,const SkPaint * paint)1910 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
1911 RETURN_ON_NULL(image);
1912 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1913 kFast_SrcRectConstraint);
1914 }
1915
1916 namespace {
1917 class LatticePaint : SkNoncopyable {
1918 public:
LatticePaint(const SkPaint * origPaint)1919 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1920 if (!origPaint) {
1921 return;
1922 }
1923 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1924 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1925 }
1926 if (origPaint->getMaskFilter()) {
1927 fPaint.writable()->setMaskFilter(nullptr);
1928 }
1929 if (origPaint->isAntiAlias()) {
1930 fPaint.writable()->setAntiAlias(false);
1931 }
1932 }
1933
get() const1934 const SkPaint* get() const {
1935 return fPaint;
1936 }
1937
1938 private:
1939 SkTCopyOnFirstWrite<SkPaint> fPaint;
1940 };
1941 } // namespace
1942
drawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,const SkPaint * paint)1943 void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1944 const SkPaint* paint) {
1945 TRACE_EVENT0("skia", TRACE_FUNC);
1946 RETURN_ON_NULL(image);
1947 if (dst.isEmpty()) {
1948 return;
1949 }
1950 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1951 LatticePaint latticePaint(paint);
1952 this->onDrawImageNine(image, center, dst, latticePaint.get());
1953 } else {
1954 this->drawImageRect(image, dst, paint);
1955 }
1956 }
1957
drawImageLattice(const SkImage * image,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)1958 void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1959 const SkPaint* paint) {
1960 TRACE_EVENT0("skia", TRACE_FUNC);
1961 RETURN_ON_NULL(image);
1962 if (dst.isEmpty()) {
1963 return;
1964 }
1965
1966 SkIRect bounds;
1967 Lattice latticePlusBounds = lattice;
1968 if (!latticePlusBounds.fBounds) {
1969 bounds = SkIRect::MakeWH(image->width(), image->height());
1970 latticePlusBounds.fBounds = &bounds;
1971 }
1972
1973 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1974 LatticePaint latticePaint(paint);
1975 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
1976 } else {
1977 this->drawImageRect(image, dst, paint);
1978 }
1979 }
1980
drawBitmap(const SkBitmap & bitmap,SkScalar dx,SkScalar dy,const SkPaint * paint)1981 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1982 TRACE_EVENT0("skia", TRACE_FUNC);
1983 if (bitmap.drawsNothing()) {
1984 return;
1985 }
1986 this->onDrawBitmap(bitmap, dx, dy, paint);
1987 }
1988
drawBitmapRect(const SkBitmap & bitmap,const SkRect & src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1989 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
1990 const SkPaint* paint, SrcRectConstraint constraint) {
1991 TRACE_EVENT0("skia", TRACE_FUNC);
1992 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
1993 return;
1994 }
1995 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
1996 }
1997
drawBitmapRect(const SkBitmap & bitmap,const SkIRect & isrc,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1998 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1999 const SkPaint* paint, SrcRectConstraint constraint) {
2000 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
2001 }
2002
drawBitmapRect(const SkBitmap & bitmap,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2003 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2004 SrcRectConstraint constraint) {
2005 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2006 constraint);
2007 }
2008
drawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)2009 void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2010 const SkPaint* paint) {
2011 TRACE_EVENT0("skia", TRACE_FUNC);
2012 if (bitmap.drawsNothing() || dst.isEmpty()) {
2013 return;
2014 }
2015 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2016 LatticePaint latticePaint(paint);
2017 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
2018 } else {
2019 this->drawBitmapRect(bitmap, dst, paint);
2020 }
2021 }
2022
drawBitmapLattice(const SkBitmap & bitmap,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)2023 void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2024 const SkPaint* paint) {
2025 TRACE_EVENT0("skia", TRACE_FUNC);
2026 if (bitmap.drawsNothing() || dst.isEmpty()) {
2027 return;
2028 }
2029
2030 SkIRect bounds;
2031 Lattice latticePlusBounds = lattice;
2032 if (!latticePlusBounds.fBounds) {
2033 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2034 latticePlusBounds.fBounds = &bounds;
2035 }
2036
2037 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2038 LatticePaint latticePaint(paint);
2039 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
2040 } else {
2041 this->drawBitmapRect(bitmap, dst, paint);
2042 }
2043 }
2044
drawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode mode,const SkRect * cull,const SkPaint * paint)2045 void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2046 const SkColor colors[], int count, SkBlendMode mode,
2047 const SkRect* cull, const SkPaint* paint) {
2048 TRACE_EVENT0("skia", TRACE_FUNC);
2049 RETURN_ON_NULL(atlas);
2050 if (count <= 0) {
2051 return;
2052 }
2053 SkASSERT(atlas);
2054 SkASSERT(tex);
2055 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2056 }
2057
drawAnnotation(const SkRect & rect,const char key[],SkData * value)2058 void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2059 TRACE_EVENT0("skia", TRACE_FUNC);
2060 if (key) {
2061 this->onDrawAnnotation(rect, key, value);
2062 }
2063 }
2064
legacy_drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2065 void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2066 const SkPaint* paint, SrcRectConstraint constraint) {
2067 if (src) {
2068 this->drawImageRect(image, *src, dst, paint, constraint);
2069 } else {
2070 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2071 dst, paint, constraint);
2072 }
2073 }
legacy_drawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2074 void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2075 const SkPaint* paint, SrcRectConstraint constraint) {
2076 if (src) {
2077 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2078 } else {
2079 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2080 dst, paint, constraint);
2081 }
2082 }
2083
private_draw_shadow_rec(const SkPath & path,const SkDrawShadowRec & rec)2084 void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
2085 TRACE_EVENT0("skia", TRACE_FUNC);
2086 this->onDrawShadowRec(path, rec);
2087 }
2088
onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)2089 void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
2090 SkPaint paint;
2091 const SkRect& pathBounds = path.getBounds();
2092
2093 DRAW_BEGIN(paint, &pathBounds)
2094 while (iter.next()) {
2095 iter.fDevice->drawShadow(path, rec);
2096 }
2097 DRAW_END
2098 }
2099
experimental_DrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)2100 void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2101 QuadAAFlags aaFlags, const SkColor4f& color,
2102 SkBlendMode mode) {
2103 TRACE_EVENT0("skia", TRACE_FUNC);
2104 // Make sure the rect is sorted before passing it along
2105 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2106 }
2107
experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[],int cnt,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkPaint * paint,SrcRectConstraint constraint)2108 void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2109 const SkPoint dstClips[],
2110 const SkMatrix preViewMatrices[],
2111 const SkPaint* paint,
2112 SrcRectConstraint constraint) {
2113 TRACE_EVENT0("skia", TRACE_FUNC);
2114 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2115 }
2116
2117 //////////////////////////////////////////////////////////////////////////////
2118 // These are the virtual drawing methods
2119 //////////////////////////////////////////////////////////////////////////////
2120
onDiscard()2121 void SkCanvas::onDiscard() {
2122 if (fSurfaceBase) {
2123 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2124 }
2125 }
2126
onDrawPaint(const SkPaint & paint)2127 void SkCanvas::onDrawPaint(const SkPaint& paint) {
2128 this->internalDrawPaint(paint);
2129 }
2130
internalDrawPaint(const SkPaint & paint)2131 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
2132 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
2133
2134 while (iter.next()) {
2135 iter.fDevice->drawPaint(draw.paint());
2136 }
2137
2138 DRAW_END
2139 }
2140
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)2141 void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2142 const SkPaint& paint) {
2143 if ((long)count <= 0) {
2144 return;
2145 }
2146
2147 SkRect r;
2148 const SkRect* bounds = nullptr;
2149 if (paint.canComputeFastBounds()) {
2150 // special-case 2 points (common for drawing a single line)
2151 if (2 == count) {
2152 r.set(pts[0], pts[1]);
2153 } else {
2154 r.setBounds(pts, SkToInt(count));
2155 }
2156 if (!r.isFinite()) {
2157 return;
2158 }
2159 SkRect storage;
2160 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2161 return;
2162 }
2163 bounds = &r;
2164 }
2165
2166 SkASSERT(pts != nullptr);
2167
2168 DRAW_BEGIN(paint, bounds)
2169
2170 while (iter.next()) {
2171 iter.fDevice->drawPoints(mode, count, pts, draw.paint());
2172 }
2173
2174 DRAW_END
2175 }
2176
needs_autodrawlooper(SkCanvas * canvas,const SkPaint & paint)2177 static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2178 return paint.getImageFilter() != nullptr;
2179 }
2180
onDrawRect(const SkRect & r,const SkPaint & paint)2181 void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
2182 SkASSERT(r.isSorted());
2183 if (paint.canComputeFastBounds()) {
2184 SkRect storage;
2185 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2186 return;
2187 }
2188 }
2189
2190 if (needs_autodrawlooper(this, paint)) {
2191 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
2192
2193 while (iter.next()) {
2194 iter.fDevice->drawRect(r, draw.paint());
2195 }
2196
2197 DRAW_END
2198 } else if (!paint.nothingToDraw()) {
2199 this->predrawNotify(&r, &paint, false);
2200 SkDrawIter iter(this);
2201 while (iter.next()) {
2202 iter.fDevice->drawRect(r, paint);
2203 }
2204 }
2205 }
2206
onDrawRegion(const SkRegion & region,const SkPaint & paint)2207 void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2208 SkRect regionRect = SkRect::Make(region.getBounds());
2209 if (paint.canComputeFastBounds()) {
2210 SkRect storage;
2211 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2212 return;
2213 }
2214 }
2215
2216 DRAW_BEGIN(paint, ®ionRect)
2217
2218 while (iter.next()) {
2219 iter.fDevice->drawRegion(region, draw.paint());
2220 }
2221
2222 DRAW_END
2223 }
2224
onDrawBehind(const SkPaint & paint)2225 void SkCanvas::onDrawBehind(const SkPaint& paint) {
2226 SkIRect bounds;
2227 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2228 for (;;) {
2229 const MCRec* rec = (const MCRec*)iter.prev();
2230 if (!rec) {
2231 return; // no backimages, so nothing to draw
2232 }
2233 if (rec->fBackImage) {
2234 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2235 rec->fBackImage->fImage->width(),
2236 rec->fBackImage->fImage->height());
2237 break;
2238 }
2239 }
2240
2241 DRAW_BEGIN(paint, nullptr)
2242
2243 while (iter.next()) {
2244 SkBaseDevice* dev = iter.fDevice;
2245
2246 dev->save();
2247 // We use clipRegion because it is already defined to operate in dev-space
2248 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2249 // but we don't want that, so we undo that before calling in.
2250 SkRegion rgn(bounds.makeOffset(dev->fOrigin));
2251 dev->clipRegion(rgn, SkClipOp::kIntersect);
2252 dev->drawPaint(draw.paint());
2253 dev->restore(fMCRec->fMatrix);
2254 }
2255
2256 DRAW_END
2257 }
2258
onDrawOval(const SkRect & oval,const SkPaint & paint)2259 void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
2260 SkASSERT(oval.isSorted());
2261 if (paint.canComputeFastBounds()) {
2262 SkRect storage;
2263 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2264 return;
2265 }
2266 }
2267
2268 DRAW_BEGIN(paint, &oval)
2269
2270 while (iter.next()) {
2271 iter.fDevice->drawOval(oval, draw.paint());
2272 }
2273
2274 DRAW_END
2275 }
2276
onDrawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)2277 void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2278 SkScalar sweepAngle, bool useCenter,
2279 const SkPaint& paint) {
2280 SkASSERT(oval.isSorted());
2281 if (paint.canComputeFastBounds()) {
2282 SkRect storage;
2283 // Note we're using the entire oval as the bounds.
2284 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2285 return;
2286 }
2287 }
2288
2289 DRAW_BEGIN(paint, &oval)
2290
2291 while (iter.next()) {
2292 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, draw.paint());
2293 }
2294
2295 DRAW_END
2296 }
2297
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)2298 void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
2299 if (paint.canComputeFastBounds()) {
2300 SkRect storage;
2301 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2302 return;
2303 }
2304 }
2305
2306 if (rrect.isRect()) {
2307 // call the non-virtual version
2308 this->SkCanvas::drawRect(rrect.getBounds(), paint);
2309 return;
2310 } else if (rrect.isOval()) {
2311 // call the non-virtual version
2312 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2313 return;
2314 }
2315
2316 DRAW_BEGIN(paint, &rrect.getBounds())
2317
2318 while (iter.next()) {
2319 iter.fDevice->drawRRect(rrect, draw.paint());
2320 }
2321
2322 DRAW_END
2323 }
2324
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)2325 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
2326 if (paint.canComputeFastBounds()) {
2327 SkRect storage;
2328 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2329 return;
2330 }
2331 }
2332
2333 DRAW_BEGIN(paint, &outer.getBounds())
2334
2335 while (iter.next()) {
2336 iter.fDevice->drawDRRect(outer, inner, draw.paint());
2337 }
2338
2339 DRAW_END
2340 }
2341
onDrawPath(const SkPath & path,const SkPaint & paint)2342 void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
2343 if (!path.isFinite()) {
2344 return;
2345 }
2346
2347 const SkRect& pathBounds = path.getBounds();
2348 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
2349 SkRect storage;
2350 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2351 return;
2352 }
2353 }
2354
2355 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
2356 if (path.isInverseFillType()) {
2357 this->internalDrawPaint(paint);
2358 return;
2359 }
2360 }
2361
2362 DRAW_BEGIN(paint, &pathBounds)
2363
2364 while (iter.next()) {
2365 iter.fDevice->drawPath(path, draw.paint());
2366 }
2367
2368 DRAW_END
2369 }
2370
canDrawBitmapAsSprite(SkScalar x,SkScalar y,int w,int h,const SkPaint & paint)2371 bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
2372 if (!paint.getImageFilter()) {
2373 return false;
2374 }
2375
2376 const SkMatrix& ctm = this->getTotalMatrix();
2377 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
2378 return false;
2379 }
2380
2381 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2382 // Once we can filter and the filter will return a result larger than itself, we should be
2383 // able to remove this constraint.
2384 // skbug.com/4526
2385 //
2386 SkPoint pt;
2387 ctm.mapXY(x, y, &pt);
2388 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2389 return ir.contains(fMCRec->fRasterClip.getBounds());
2390 }
2391
2392 // Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2393 // given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2394 // null.
init_image_paint(SkPaint * real,const SkPaint * paintParam)2395 static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2396 if (paintParam) {
2397 *real = *paintParam;
2398 real->setStyle(SkPaint::kFill_Style);
2399 real->setPathEffect(nullptr);
2400 paintParam = real;
2401 }
2402 return paintParam;
2403 }
2404
onDrawImage(const SkImage * image,SkScalar x,SkScalar y,const SkPaint * paint)2405 void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
2406 SkPaint realPaint;
2407 paint = init_image_paint(&realPaint, paint);
2408
2409 SkRect bounds = SkRect::MakeXYWH(x, y,
2410 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
2411 if (nullptr == paint || paint->canComputeFastBounds()) {
2412 SkRect tmp = bounds;
2413 if (paint) {
2414 paint->computeFastBounds(tmp, &tmp);
2415 }
2416 if (this->quickReject(tmp)) {
2417 return;
2418 }
2419 }
2420 // At this point we need a real paint object. If the caller passed null, then we should
2421 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2422 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2423 paint = &realPaint;
2424
2425 sk_sp<SkSpecialImage> special;
2426 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2427 *paint);
2428 if (drawAsSprite && paint->getImageFilter()) {
2429 special = this->getDevice()->makeSpecial(image);
2430 if (!special) {
2431 drawAsSprite = false;
2432 }
2433 }
2434
2435 DRAW_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2436
2437 while (iter.next()) {
2438 const SkPaint& pnt = draw.paint();
2439 if (special) {
2440 SkPoint pt;
2441 iter.fDevice->ctm().mapXY(x, y, &pt);
2442 iter.fDevice->drawSpecial(special.get(),
2443 SkScalarRoundToInt(pt.fX),
2444 SkScalarRoundToInt(pt.fY), pnt,
2445 nullptr, SkMatrix::I());
2446 } else {
2447 iter.fDevice->drawImageRect(
2448 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2449 kStrict_SrcRectConstraint);
2450 }
2451 }
2452
2453 DRAW_END
2454 }
2455
onDrawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2456 void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2457 const SkPaint* paint, SrcRectConstraint constraint) {
2458 SkPaint realPaint;
2459 paint = init_image_paint(&realPaint, paint);
2460
2461 if (nullptr == paint || paint->canComputeFastBounds()) {
2462 SkRect storage = dst;
2463 if (paint) {
2464 paint->computeFastBounds(dst, &storage);
2465 }
2466 if (this->quickReject(storage)) {
2467 return;
2468 }
2469 }
2470 paint = &realPaint;
2471
2472 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
2473
2474 while (iter.next()) {
2475 iter.fDevice->drawImageRect(image, src, dst, draw.paint(), constraint);
2476 }
2477
2478 DRAW_END
2479 }
2480
onDrawBitmap(const SkBitmap & bitmap,SkScalar x,SkScalar y,const SkPaint * paint)2481 void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
2482 SkDEBUGCODE(bitmap.validate();)
2483
2484 if (bitmap.drawsNothing()) {
2485 return;
2486 }
2487
2488 SkPaint realPaint;
2489 init_image_paint(&realPaint, paint);
2490 paint = &realPaint;
2491
2492 SkRect bounds;
2493 bitmap.getBounds(&bounds);
2494 bounds.offset(x, y);
2495 bool canFastBounds = paint->canComputeFastBounds();
2496 if (canFastBounds) {
2497 SkRect storage;
2498 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
2499 return;
2500 }
2501 }
2502
2503 sk_sp<SkSpecialImage> special;
2504 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2505 bitmap.height(), *paint);
2506 if (drawAsSprite && paint->getImageFilter()) {
2507 special = this->getDevice()->makeSpecial(bitmap);
2508 if (!special) {
2509 drawAsSprite = false;
2510 }
2511 }
2512
2513 DRAW_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2514
2515 while (iter.next()) {
2516 const SkPaint& pnt = draw.paint();
2517 if (special) {
2518 SkPoint pt;
2519 iter.fDevice->ctm().mapXY(x, y, &pt);
2520 iter.fDevice->drawSpecial(special.get(),
2521 SkScalarRoundToInt(pt.fX),
2522 SkScalarRoundToInt(pt.fY), pnt,
2523 nullptr, SkMatrix::I());
2524 } else {
2525 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2526 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2527 kStrict_SrcRectConstraint);
2528 }
2529 }
2530
2531 DRAW_END
2532 }
2533
2534 // 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)2535 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
2536 const SkRect& dst, const SkPaint* paint,
2537 SrcRectConstraint constraint) {
2538 if (bitmap.drawsNothing() || dst.isEmpty()) {
2539 return;
2540 }
2541
2542 if (nullptr == paint || paint->canComputeFastBounds()) {
2543 SkRect storage;
2544 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2545 return;
2546 }
2547 }
2548
2549 SkLazyPaint lazy;
2550 if (nullptr == paint) {
2551 paint = lazy.init();
2552 }
2553
2554 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
2555
2556 while (iter.next()) {
2557 iter.fDevice->drawBitmapRect(bitmap, src, dst, draw.paint(), constraint);
2558 }
2559
2560 DRAW_END
2561 }
2562
onDrawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2563 void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2564 const SkPaint* paint, SrcRectConstraint constraint) {
2565 SkDEBUGCODE(bitmap.validate();)
2566 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
2567 }
2568
onDrawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,const SkPaint * paint)2569 void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2570 const SkPaint* paint) {
2571 SkPaint realPaint;
2572 paint = init_image_paint(&realPaint, paint);
2573
2574 if (nullptr == paint || paint->canComputeFastBounds()) {
2575 SkRect storage;
2576 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2577 return;
2578 }
2579 }
2580 paint = &realPaint;
2581
2582 DRAW_BEGIN(*paint, &dst)
2583
2584 while (iter.next()) {
2585 iter.fDevice->drawImageNine(image, center, dst, draw.paint());
2586 }
2587
2588 DRAW_END
2589 }
2590
onDrawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)2591 void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2592 const SkPaint* paint) {
2593 SkDEBUGCODE(bitmap.validate();)
2594 SkPaint realPaint;
2595 paint = init_image_paint(&realPaint, paint);
2596
2597 if (nullptr == paint || paint->canComputeFastBounds()) {
2598 SkRect storage;
2599 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2600 return;
2601 }
2602 }
2603 paint = &realPaint;
2604
2605 DRAW_BEGIN(*paint, &dst)
2606
2607 while (iter.next()) {
2608 iter.fDevice->drawBitmapNine(bitmap, center, dst, draw.paint());
2609 }
2610
2611 DRAW_END
2612 }
2613
onDrawImageLattice(const SkImage * image,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)2614 void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2615 const SkPaint* paint) {
2616 SkPaint realPaint;
2617 paint = init_image_paint(&realPaint, paint);
2618
2619 if (nullptr == paint || paint->canComputeFastBounds()) {
2620 SkRect storage;
2621 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2622 return;
2623 }
2624 }
2625 paint = &realPaint;
2626
2627 DRAW_BEGIN(*paint, &dst)
2628
2629 while (iter.next()) {
2630 iter.fDevice->drawImageLattice(image, lattice, dst, draw.paint());
2631 }
2632
2633 DRAW_END
2634 }
2635
onDrawBitmapLattice(const SkBitmap & bitmap,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)2636 void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2637 const SkRect& dst, const SkPaint* paint) {
2638 SkPaint realPaint;
2639 paint = init_image_paint(&realPaint, paint);
2640
2641 if (nullptr == paint || paint->canComputeFastBounds()) {
2642 SkRect storage;
2643 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2644 return;
2645 }
2646 }
2647 paint = &realPaint;
2648
2649 DRAW_BEGIN(*paint, &dst)
2650
2651 while (iter.next()) {
2652 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, draw.paint());
2653 }
2654
2655 DRAW_END
2656 }
2657
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2658 void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2659 const SkPaint& paint) {
2660 SkRect storage;
2661 const SkRect* bounds = nullptr;
2662 if (paint.canComputeFastBounds()) {
2663 storage = blob->bounds().makeOffset(x, y);
2664 SkRect tmp;
2665 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2666 return;
2667 }
2668 bounds = &storage;
2669 }
2670
2671 // We cannot filter in the looper as we normally do, because the paint is
2672 // incomplete at this point (text-related attributes are embedded within blob run paints).
2673 DRAW_BEGIN(paint, bounds)
2674
2675 while (iter.next()) {
2676 fScratchGlyphRunBuilder->drawTextBlob(draw.paint(), *blob, {x, y}, iter.fDevice);
2677 }
2678
2679 DRAW_END
2680 }
2681
2682 // 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)2683 void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
2684 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2685 TRACE_EVENT0("skia", TRACE_FUNC);
2686 if (byteLength) {
2687 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
2688 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
2689 }
2690 }
2691
drawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2692 void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2693 const SkPaint& paint) {
2694 TRACE_EVENT0("skia", TRACE_FUNC);
2695 RETURN_ON_NULL(blob);
2696 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
2697 this->onDrawTextBlob(blob, x, y, paint);
2698 }
2699
onDrawVerticesObject(const SkVertices * vertices,const SkVertices::Bone bones[],int boneCount,SkBlendMode bmode,const SkPaint & paint)2700 void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
2701 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
2702 DRAW_BEGIN(paint, nullptr)
2703
2704 while (iter.next()) {
2705 // In the common case of one iteration we could std::move vertices here.
2706 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, draw.paint());
2707 }
2708
2709 DRAW_END
2710 }
2711
drawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)2712 void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2713 const SkPoint texCoords[4], SkBlendMode bmode,
2714 const SkPaint& paint) {
2715 TRACE_EVENT0("skia", TRACE_FUNC);
2716 if (nullptr == cubics) {
2717 return;
2718 }
2719
2720 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
2721 }
2722
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)2723 void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2724 const SkPoint texCoords[4], SkBlendMode bmode,
2725 const SkPaint& paint) {
2726 // Since a patch is always within the convex hull of the control points, we discard it when its
2727 // bounding rectangle is completely outside the current clip.
2728 SkRect bounds;
2729 bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts);
2730 if (this->quickReject(bounds)) {
2731 return;
2732 }
2733
2734 DRAW_BEGIN(paint, nullptr)
2735
2736 while (iter.next()) {
2737 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
2738 }
2739
2740 DRAW_END
2741 }
2742
drawDrawable(SkDrawable * dr,SkScalar x,SkScalar y)2743 void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2744 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2745 TRACE_EVENT0("skia", TRACE_FUNC);
2746 #endif
2747 RETURN_ON_NULL(dr);
2748 if (x || y) {
2749 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2750 this->onDrawDrawable(dr, &matrix);
2751 } else {
2752 this->onDrawDrawable(dr, nullptr);
2753 }
2754 }
2755
drawDrawable(SkDrawable * dr,const SkMatrix * matrix)2756 void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2757 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2758 TRACE_EVENT0("skia", TRACE_FUNC);
2759 #endif
2760 RETURN_ON_NULL(dr);
2761 if (matrix && matrix->isIdentity()) {
2762 matrix = nullptr;
2763 }
2764 this->onDrawDrawable(dr, matrix);
2765 }
2766
onDrawDrawable(SkDrawable * dr,const SkMatrix * matrix)2767 void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2768 // drawable bounds are no longer reliable (e.g. android displaylist)
2769 // so don't use them for quick-reject
2770 this->getDevice()->drawDrawable(dr, matrix, this);
2771 }
2772
onDrawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode bmode,const SkRect * cull,const SkPaint * paint)2773 void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2774 const SkColor colors[], int count, SkBlendMode bmode,
2775 const SkRect* cull, const SkPaint* paint) {
2776 if (cull && this->quickReject(*cull)) {
2777 return;
2778 }
2779
2780 SkPaint pnt;
2781 if (paint) {
2782 pnt = *paint;
2783 }
2784
2785 DRAW_BEGIN(pnt, nullptr)
2786 while (iter.next()) {
2787 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
2788 }
2789 DRAW_END
2790 }
2791
onDrawAnnotation(const SkRect & rect,const char key[],SkData * value)2792 void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2793 SkASSERT(key);
2794
2795 SkPaint paint;
2796 DRAW_BEGIN(paint, nullptr)
2797 while (iter.next()) {
2798 iter.fDevice->drawAnnotation(rect, key, value);
2799 }
2800 DRAW_END
2801 }
2802
onDrawEdgeAAQuad(const SkRect & r,const SkPoint clip[4],QuadAAFlags edgeAA,const SkColor4f & color,SkBlendMode mode)2803 void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2804 const SkColor4f& color, SkBlendMode mode) {
2805 SkASSERT(r.isSorted());
2806
2807 // If this used a paint, it would be a filled color with blend mode, which does not
2808 // need to use an autodraw loop, so use SkDrawIter directly.
2809 if (this->quickReject(r)) {
2810 return;
2811 }
2812
2813 this->predrawNotify(&r, nullptr, false);
2814 SkDrawIter iter(this);
2815 while(iter.next()) {
2816 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2817 }
2818 }
2819
onDrawEdgeAAImageSet(const ImageSetEntry imageSet[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkPaint * paint,SrcRectConstraint constraint)2820 void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2821 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2822 const SkPaint* paint, SrcRectConstraint constraint) {
2823 if (count <= 0) {
2824 // Nothing to draw
2825 return;
2826 }
2827
2828 SkPaint realPaint;
2829 init_image_paint(&realPaint, paint);
2830
2831 // We could calculate the set's dstRect union to always check quickReject(), but we can't reject
2832 // individual entries and Chromium's occlusion culling already makes it likely that at least one
2833 // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1),
2834 // or we need it for the autolooper (since it greatly improves image filter perf).
2835 bool needsAutoLooper = needs_autodrawlooper(this, realPaint);
2836 bool setBoundsValid = count == 1 || needsAutoLooper;
2837 SkRect setBounds = imageSet[0].fDstRect;
2838 if (imageSet[0].fMatrixIndex >= 0) {
2839 // Account for the per-entry transform that is applied prior to the CTM when drawing
2840 preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds);
2841 }
2842 if (needsAutoLooper) {
2843 for (int i = 1; i < count; ++i) {
2844 SkRect entryBounds = imageSet[i].fDstRect;
2845 if (imageSet[i].fMatrixIndex >= 0) {
2846 preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds);
2847 }
2848 setBounds.joinPossiblyEmptyRect(entryBounds);
2849 }
2850 }
2851
2852 // If we happen to have the draw bounds, though, might as well check quickReject().
2853 if (setBoundsValid && realPaint.canComputeFastBounds()) {
2854 SkRect tmp;
2855 if (this->quickReject(realPaint.computeFastBounds(setBounds, &tmp))) {
2856 return;
2857 }
2858 }
2859
2860 if (needsAutoLooper) {
2861 SkASSERT(setBoundsValid);
2862 DRAW_BEGIN(realPaint, &setBounds)
2863 while (iter.next()) {
2864 iter.fDevice->drawEdgeAAImageSet(
2865 imageSet, count, dstClips, preViewMatrices, draw.paint(), constraint);
2866 }
2867 DRAW_END
2868 } else {
2869 this->predrawNotify();
2870 SkDrawIter iter(this);
2871 while(iter.next()) {
2872 iter.fDevice->drawEdgeAAImageSet(
2873 imageSet, count, dstClips, preViewMatrices, realPaint, constraint);
2874 }
2875 }
2876 }
2877
2878 //////////////////////////////////////////////////////////////////////////////
2879 // These methods are NOT virtual, and therefore must call back into virtual
2880 // methods, rather than actually drawing themselves.
2881 //////////////////////////////////////////////////////////////////////////////
2882
drawColor(SkColor c,SkBlendMode mode)2883 void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
2884 SkPaint paint;
2885 paint.setColor(c);
2886 paint.setBlendMode(mode);
2887 this->drawPaint(paint);
2888 }
2889
drawPoint(SkScalar x,SkScalar y,const SkPaint & paint)2890 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2891 const SkPoint pt = { x, y };
2892 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2893 }
2894
drawLine(SkScalar x0,SkScalar y0,SkScalar x1,SkScalar y1,const SkPaint & paint)2895 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
2896 SkPoint pts[2];
2897 pts[0].set(x0, y0);
2898 pts[1].set(x1, y1);
2899 this->drawPoints(kLines_PointMode, 2, pts, paint);
2900 }
2901
drawCircle(SkScalar cx,SkScalar cy,SkScalar radius,const SkPaint & paint)2902 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
2903 if (radius < 0) {
2904 radius = 0;
2905 }
2906
2907 SkRect r;
2908 r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
2909 this->drawOval(r, paint);
2910 }
2911
drawRoundRect(const SkRect & r,SkScalar rx,SkScalar ry,const SkPaint & paint)2912 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2913 const SkPaint& paint) {
2914 if (rx > 0 && ry > 0) {
2915 SkRRect rrect;
2916 rrect.setRectXY(r, rx, ry);
2917 this->drawRRect(rrect, paint);
2918 } else {
2919 this->drawRect(r, paint);
2920 }
2921 }
2922
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)2923 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2924 SkScalar sweepAngle, bool useCenter,
2925 const SkPaint& paint) {
2926 TRACE_EVENT0("skia", TRACE_FUNC);
2927 if (oval.isEmpty() || !sweepAngle) {
2928 return;
2929 }
2930 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
2931 }
2932
2933 ///////////////////////////////////////////////////////////////////////////////
2934 #ifdef SK_DISABLE_SKPICTURE
drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2935 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
2936
2937
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2938 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2939 const SkPaint* paint) {}
2940 #else
2941 /**
2942 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2943 * against the playback cost of recursing into the subpicture to get at its actual ops.
2944 *
2945 * For now we pick a conservatively small value, though measurement (and other heuristics like
2946 * the type of ops contained) may justify changing this value.
2947 */
2948 #define kMaxPictureOpsToUnrollInsteadOfRef 1
2949
drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2950 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2951 TRACE_EVENT0("skia", TRACE_FUNC);
2952 RETURN_ON_NULL(picture);
2953
2954 if (matrix && matrix->isIdentity()) {
2955 matrix = nullptr;
2956 }
2957 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2958 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2959 picture->playback(this);
2960 } else {
2961 this->onDrawPicture(picture, matrix, paint);
2962 }
2963 }
2964
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2965 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2966 const SkPaint* paint) {
2967 if (!paint || paint->canComputeFastBounds()) {
2968 SkRect bounds = picture->cullRect();
2969 if (paint) {
2970 paint->computeFastBounds(bounds, &bounds);
2971 }
2972 if (matrix) {
2973 matrix->mapRect(&bounds);
2974 }
2975 if (this->quickReject(bounds)) {
2976 return;
2977 }
2978 }
2979
2980 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2981 picture->playback(this);
2982 }
2983 #endif
2984
2985 ///////////////////////////////////////////////////////////////////////////////
2986 ///////////////////////////////////////////////////////////////////////////////
2987
LayerIter(SkCanvas * canvas)2988 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
2989 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
2990
2991 SkASSERT(canvas);
2992
2993 fImpl = new (fStorage) SkDrawIter(canvas);
2994 fDone = !fImpl->next();
2995 }
2996
~LayerIter()2997 SkCanvas::LayerIter::~LayerIter() {
2998 fImpl->~SkDrawIter();
2999 }
3000
next()3001 void SkCanvas::LayerIter::next() {
3002 fDone = !fImpl->next();
3003 }
3004
device() const3005 SkBaseDevice* SkCanvas::LayerIter::device() const {
3006 return fImpl->fDevice;
3007 }
3008
matrix() const3009 const SkMatrix& SkCanvas::LayerIter::matrix() const {
3010 return fImpl->fDevice->ctm();
3011 }
3012
paint() const3013 const SkPaint& SkCanvas::LayerIter::paint() const {
3014 const SkPaint* paint = fImpl->getPaint();
3015 if (nullptr == paint) {
3016 paint = &fDefaultPaint;
3017 }
3018 return *paint;
3019 }
3020
clipBounds() const3021 SkIRect SkCanvas::LayerIter::clipBounds() const {
3022 return fImpl->fDevice->getGlobalBounds();
3023 }
3024
x() const3025 int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
y() const3026 int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
3027
3028 ///////////////////////////////////////////////////////////////////////////////
3029
3030 SkCanvas::ImageSetEntry::ImageSetEntry() = default;
3031 SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
3032 SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
3033 SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
3034
ImageSetEntry(sk_sp<const SkImage> image,const SkRect & srcRect,const SkRect & dstRect,int matrixIndex,float alpha,unsigned aaFlags,bool hasClip)3035 SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
3036 const SkRect& dstRect, int matrixIndex, float alpha,
3037 unsigned aaFlags, bool hasClip)
3038 : fImage(std::move(image))
3039 , fSrcRect(srcRect)
3040 , fDstRect(dstRect)
3041 , fMatrixIndex(matrixIndex)
3042 , fAlpha(alpha)
3043 , fAAFlags(aaFlags)
3044 , fHasClip(hasClip) {}
3045
ImageSetEntry(sk_sp<const SkImage> image,const SkRect & srcRect,const SkRect & dstRect,float alpha,unsigned aaFlags)3046 SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
3047 const SkRect& dstRect, float alpha, unsigned aaFlags)
3048 : fImage(std::move(image))
3049 , fSrcRect(srcRect)
3050 , fDstRect(dstRect)
3051 , fAlpha(alpha)
3052 , fAAFlags(aaFlags) {}
3053
3054 ///////////////////////////////////////////////////////////////////////////////
3055
MakeRasterDirect(const SkImageInfo & info,void * pixels,size_t rowBytes,const SkSurfaceProps * props)3056 std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3057 size_t rowBytes, const SkSurfaceProps* props) {
3058 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
3059 return nullptr;
3060 }
3061
3062 SkBitmap bitmap;
3063 if (!bitmap.installPixels(info, pixels, rowBytes)) {
3064 return nullptr;
3065 }
3066
3067 return props ?
3068 skstd::make_unique<SkCanvas>(bitmap, *props) :
3069 skstd::make_unique<SkCanvas>(bitmap);
3070 }
3071
3072 ///////////////////////////////////////////////////////////////////////////////
3073
SkNoDrawCanvas(int width,int height)3074 SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3075 : INHERITED(SkIRect::MakeWH(width, height)) {}
3076
SkNoDrawCanvas(const SkIRect & bounds)3077 SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3078 : INHERITED(bounds) {}
3079
SkNoDrawCanvas(sk_sp<SkBaseDevice> device)3080 SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
3081 : INHERITED(device) {}
3082
getSaveLayerStrategy(const SaveLayerRec & rec)3083 SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3084 (void)this->INHERITED::getSaveLayerStrategy(rec);
3085 return kNoLayer_SaveLayerStrategy;
3086 }
3087
onDoSaveBehind(const SkRect *)3088 bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
3089 return false;
3090 }
3091
3092 ///////////////////////////////////////////////////////////////////////////////
3093
3094 static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3095 static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3096 static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3097 static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3098 static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3099 static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
3100
3101 ///////////////////////////////////////////////////////////////////////////////////////////////////
3102
accessTopRasterHandle() const3103 SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3104 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3105 const auto& dev = fMCRec->fTopLayer->fDevice;
3106 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3107 SkIPoint origin = dev->getOrigin();
3108 SkMatrix ctm = this->getTotalMatrix();
3109 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3110
3111 SkIRect clip = fMCRec->fRasterClip.getBounds();
3112 clip.offset(-origin.x(), -origin.y());
3113 if (!clip.intersect({0, 0, dev->width(), dev->height()})) {
3114 clip.setEmpty();
3115 }
3116
3117 fAllocator->updateHandle(handle, ctm, clip);
3118 return handle;
3119 }
3120 return nullptr;
3121 }
3122
install(SkBitmap * bm,const SkImageInfo & info,const SkRasterHandleAllocator::Rec & rec)3123 static bool install(SkBitmap* bm, const SkImageInfo& info,
3124 const SkRasterHandleAllocator::Rec& rec) {
3125 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
3126 }
3127
allocBitmap(const SkImageInfo & info,SkBitmap * bm)3128 SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3129 SkBitmap* bm) {
3130 SkRasterHandleAllocator::Rec rec;
3131 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3132 return nullptr;
3133 }
3134 return rec.fHandle;
3135 }
3136
3137 std::unique_ptr<SkCanvas>
MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,const SkImageInfo & info,const Rec * rec)3138 SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3139 const SkImageInfo& info, const Rec* rec) {
3140 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
3141 return nullptr;
3142 }
3143
3144 SkBitmap bm;
3145 Handle hndl;
3146
3147 if (rec) {
3148 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3149 } else {
3150 hndl = alloc->allocBitmap(info, &bm);
3151 }
3152 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3153 }
3154
3155 ///////////////////////////////////////////////////////////////////////////////////////////////////
3156