1 /*
2 * Copyright 2008 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkCanvas.h"
9
10 #include "include/core/SkColorFilter.h"
11 #include "include/core/SkImage.h"
12 #include "include/core/SkImageFilter.h"
13 #include "include/core/SkPathEffect.h"
14 #include "include/core/SkPicture.h"
15 #include "include/core/SkRRect.h"
16 #include "include/core/SkRasterHandleAllocator.h"
17 #include "include/core/SkString.h"
18 #include "include/core/SkTextBlob.h"
19 #include "include/core/SkVertices.h"
20 #include "include/effects/SkRuntimeEffect.h"
21 #include "include/private/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/SkMarkerStack.h"
35 #include "src/core/SkMatrixPriv.h"
36 #include "src/core/SkMatrixUtils.h"
37 #include "src/core/SkPaintPriv.h"
38 #include "src/core/SkRasterClip.h"
39 #include "src/core/SkSpecialImage.h"
40 #include "src/core/SkStrikeCache.h"
41 #include "src/core/SkTLazy.h"
42 #include "src/core/SkTextFormatParams.h"
43 #include "src/core/SkTraceEvent.h"
44 #include "src/core/SkVerticesPriv.h"
45 #include "src/image/SkImage_Base.h"
46 #include "src/image/SkSurface_Base.h"
47 #include "src/utils/SkPatchUtils.h"
48
49 #include <memory>
50 #include <new>
51
52 #if SK_SUPPORT_GPU
53 #include "include/gpu/GrDirectContext.h"
54 #include "src/gpu/SkGr.h"
55 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
56 # include "src/gpu/GrRenderTarget.h"
57 # include "src/gpu/GrRenderTargetProxy.h"
58 # include "src/gpu/GrSurfaceDrawContext.h"
59 #endif
60 #endif
61
62 #define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
63 #define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
64
65 // This is a test: static_assert with no message is a c++17 feature,
66 // and std::max() is constexpr only since the c++14 stdlib.
67 static_assert(std::max(3,4) == 4);
68
69 ///////////////////////////////////////////////////////////////////////////////////////////////////
70
71 /*
72 * Return true if the drawing this rect would hit every pixels in the canvas.
73 *
74 * Returns false if
75 * - rect does not contain the canvas' bounds
76 * - paint is not fill
77 * - paint would blur or otherwise change the coverage of the rect
78 */
wouldOverwriteEntireSurface(const SkRect * rect,const SkPaint * paint,ShaderOverrideOpacity overrideOpacity) const79 bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
80 ShaderOverrideOpacity overrideOpacity) const {
81 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
82 (int)kNone_ShaderOverrideOpacity,
83 "need_matching_enums0");
84 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
85 (int)kOpaque_ShaderOverrideOpacity,
86 "need_matching_enums1");
87 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
88 (int)kNotOpaque_ShaderOverrideOpacity,
89 "need_matching_enums2");
90
91 const SkISize size = this->getBaseLayerSize();
92 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
93
94 // if we're clipped at all, we can't overwrite the entire surface
95 {
96 const SkBaseDevice* base = this->baseDevice();
97 const SkBaseDevice* top = this->topDevice();
98 if (base != top) {
99 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
100 }
101 if (!base->clipIsWideOpen()) {
102 return false;
103 }
104 }
105
106 if (rect) {
107 if (!this->getTotalMatrix().isScaleTranslate()) {
108 return false; // conservative
109 }
110
111 SkRect devRect;
112 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
113 if (!devRect.contains(bounds)) {
114 return false;
115 }
116 }
117
118 if (paint) {
119 SkPaint::Style paintStyle = paint->getStyle();
120 if (!(paintStyle == SkPaint::kFill_Style ||
121 paintStyle == SkPaint::kStrokeAndFill_Style)) {
122 return false;
123 }
124 if (paint->getMaskFilter() || paint->getPathEffect() || paint->getImageFilter()) {
125 return false; // conservative
126 }
127 }
128 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
129 }
130
131 ///////////////////////////////////////////////////////////////////////////////////////////////////
132
133 // experimental for faster tiled drawing...
134 //#define SK_TRACE_SAVERESTORE
135
136 #ifdef SK_TRACE_SAVERESTORE
137 static int gLayerCounter;
inc_layer()138 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
dec_layer()139 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
140
141 static int gRecCounter;
inc_rec()142 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
dec_rec()143 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
144
145 static int gCanvasCounter;
inc_canvas()146 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
dec_canvas()147 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
148 #else
149 #define inc_layer()
150 #define dec_layer()
151 #define inc_rec()
152 #define dec_rec()
153 #define inc_canvas()
154 #define dec_canvas()
155 #endif
156
predrawNotify(bool willOverwritesEntireSurface)157 void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
158 if (fSurfaceBase) {
159 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
160 ? SkSurface::kDiscard_ContentChangeMode
161 : SkSurface::kRetain_ContentChangeMode);
162 }
163 }
164
predrawNotify(const SkRect * rect,const SkPaint * paint,ShaderOverrideOpacity overrideOpacity)165 void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
166 ShaderOverrideOpacity overrideOpacity) {
167 if (fSurfaceBase) {
168 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
169 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
170 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
171 // and therefore we don't care which mode we're in.
172 //
173 if (fSurfaceBase->outstandingImageSnapshot()) {
174 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
175 mode = SkSurface::kDiscard_ContentChangeMode;
176 }
177 }
178 fSurfaceBase->aboutToDraw(mode);
179 }
180 }
181
182 ///////////////////////////////////////////////////////////////////////////////
183
184 namespace {
185 // Canvases maintain a sparse stack of layers, where the top-most layer receives the drawing,
186 // clip, and matrix commands. There is a layer per call to saveLayer() using the
187 // kFullLayer_SaveLayerStrategy.
188 struct Layer {
189 sk_sp<SkBaseDevice> fDevice;
190 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
191 // original CTM; used by imagefilter in saveLayer
192 SkM44 fStashedMatrix;
193
Layer__anon839d15e90111::Layer194 Layer(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkM44& stashed)
195 : fDevice(std::move(device))
196 , fPaint(paint ? std::make_unique<SkPaint>(*paint) : nullptr)
197 , fStashedMatrix(stashed) {
198 SkASSERT(fDevice);
199 }
200 };
201
202 // Encapsulate state needed to restore from saveBehind()
203 struct BackImage {
204 sk_sp<SkSpecialImage> fImage;
205 SkIPoint fLoc;
206 };
207
208 enum class CheckForOverwrite : bool {
209 kNo = false,
210 kYes = true
211 };
212
213 } // namespace
214
215 /* This is the record we keep for each save/restore level in the stack.
216 Since a level optionally copies the matrix and/or stack, we have pointers
217 for these fields. If the value is copied for this level, the copy is
218 stored in the ...Storage field, and the pointer points to that. If the
219 value is not copied for this level, we ignore ...Storage, and just point
220 at the corresponding value in the previous level in the stack.
221 */
222 class SkCanvas::MCRec {
223 public:
224 // If not null, this MCRec corresponds with the saveLayer() record that made the layer.
225 // The base "layer" is not stored here, since it is stored inline in SkCanvas and has no
226 // restoration behavior.
227 std::unique_ptr<Layer> fLayer;
228
229 // This points to the device of the top-most layer (which may be lower in the stack), or
230 // to the canvas's fBaseDevice. The MCRec does not own the device.
231 SkBaseDevice* fDevice;
232
233 std::unique_ptr<BackImage> fBackImage;
234 SkM44 fMatrix;
235 int fDeferredSaveCount;
236
MCRec(SkBaseDevice * device)237 MCRec(SkBaseDevice* device)
238 : fLayer(nullptr)
239 , fDevice(device)
240 , fBackImage(nullptr)
241 , fDeferredSaveCount(0) {
242 SkASSERT(fDevice);
243 fMatrix.setIdentity();
244 inc_rec();
245 }
MCRec(const MCRec & prev)246 MCRec(const MCRec& prev)
247 : fLayer(nullptr)
248 , fDevice(prev.fDevice)
249 , fMatrix(prev.fMatrix)
250 , fDeferredSaveCount(0) {
251 SkASSERT(fDevice);
252 inc_rec();
253 }
~MCRec()254 ~MCRec() {
255 dec_rec();
256 }
257
newLayer(sk_sp<SkBaseDevice> layerDevice,const SkPaint * restorePaint,const SkM44 & stashedMatrix)258 void newLayer(sk_sp<SkBaseDevice> layerDevice, const SkPaint* restorePaint,
259 const SkM44& stashedMatrix) {
260 SkASSERT(!fBackImage);
261 fLayer = std::make_unique<Layer>(std::move(layerDevice), restorePaint, stashedMatrix);
262 fDevice = fLayer->fDevice.get();
263 }
264
reset(SkBaseDevice * device)265 void reset(SkBaseDevice* device) {
266 SkASSERT(device);
267 SkASSERT(fDeferredSaveCount == 0);
268 fDevice = device;
269 fMatrix.setIdentity();
270 }
271 };
272
273 class SkCanvas::AutoUpdateQRBounds {
274 public:
AutoUpdateQRBounds(SkCanvas * canvas)275 explicit AutoUpdateQRBounds(SkCanvas* canvas) : fCanvas(canvas) {
276 // pre-condition, fQuickRejectBounds and other state should be valid before anything
277 // modifies the device's clip.
278 fCanvas->validateClip();
279 }
~AutoUpdateQRBounds()280 ~AutoUpdateQRBounds() {
281 fCanvas->fQuickRejectBounds = fCanvas->computeDeviceClipBounds();
282 // post-condition, we should remain valid after re-computing the bounds
283 fCanvas->validateClip();
284 }
285
286 private:
287 SkCanvas* fCanvas;
288
289 AutoUpdateQRBounds(AutoUpdateQRBounds&&) = delete;
290 AutoUpdateQRBounds(const AutoUpdateQRBounds&) = delete;
291 AutoUpdateQRBounds& operator=(AutoUpdateQRBounds&&) = delete;
292 AutoUpdateQRBounds& operator=(const AutoUpdateQRBounds&) = delete;
293 };
294
295 /////////////////////////////////////////////////////////////////////////////
296 // Attempts to convert an image filter to its equivalent color filter, which if possible, modifies
297 // the paint to compose the image filter's color filter into the paint's color filter slot.
298 // Returns true if the paint has been modified.
299 // Requires the paint to have an image filter and the copy-on-write be initialized.
image_to_color_filter(SkPaint * paint)300 static bool image_to_color_filter(SkPaint* paint) {
301 SkASSERT(SkToBool(paint) && paint->getImageFilter());
302
303 SkColorFilter* imgCFPtr;
304 if (!paint->getImageFilter()->asAColorFilter(&imgCFPtr)) {
305 return false;
306 }
307 sk_sp<SkColorFilter> imgCF(imgCFPtr);
308
309 SkColorFilter* paintCF = paint->getColorFilter();
310 if (paintCF) {
311 // The paint has both a colorfilter(paintCF) and an imagefilter-that-is-a-colorfilter(imgCF)
312 // and we need to combine them into a single colorfilter.
313 imgCF = imgCF->makeComposed(sk_ref_sp(paintCF));
314 }
315
316 paint->setColorFilter(std::move(imgCF));
317 paint->setImageFilter(nullptr);
318 return true;
319 }
320
321 /**
322 * We implement ImageFilters for a given draw by creating a layer, then applying the
323 * imagefilter to the pixels of that layer (its backing surface/image), and then
324 * we call restore() to xfer that layer to the main canvas.
325 *
326 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
327 * 2. Generate the src pixels:
328 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
329 * return (fPaint). We then draw the primitive (using srcover) into a cleared
330 * buffer/surface.
331 * 3. Restore the layer created in #1
332 * The imagefilter is passed the buffer/surface from the layer (now filled with the
333 * src pixels of the primitive). It returns a new "filtered" buffer, which we
334 * draw onto the previous layer using the xfermode from the original paint.
335 */
336 class AutoLayerForImageFilter {
337 public:
338 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
339 // paint. It's used to determine the size of the offscreen layer for filters.
340 // If null, the clip will be used instead.
341 //
342 // Draw functions should use layer->paint() instead of the passed-in paint.
AutoLayerForImageFilter(SkCanvas * canvas,const SkPaint & paint,const SkRect * rawBounds=nullptr,CheckForOverwrite checkOverwrite=CheckForOverwrite::kNo,SkCanvas::ShaderOverrideOpacity overrideOpacity=SkCanvas::kNone_ShaderOverrideOpacity)343 AutoLayerForImageFilter(SkCanvas* canvas,
344 const SkPaint& paint,
345 const SkRect* rawBounds = nullptr,
346 CheckForOverwrite checkOverwrite = CheckForOverwrite::kNo,
347 SkCanvas::ShaderOverrideOpacity overrideOpacity =
348 SkCanvas::kNone_ShaderOverrideOpacity)
349 : fPaint(paint)
350 , fCanvas(canvas)
351 , fTempLayerForImageFilter(false) {
352 SkDEBUGCODE(fSaveCount = canvas->getSaveCount();)
353
354 if (checkOverwrite == CheckForOverwrite::kYes) {
355 canvas->predrawNotify(rawBounds, &fPaint, overrideOpacity);
356 } else {
357 canvas->predrawNotify();
358 }
359
360 if (fPaint.getImageFilter() && !image_to_color_filter(&fPaint)) {
361 // The draw paint has an image filter that couldn't be simplified to an equivalent
362 // color filter, so we have to inject an automatic saveLayer().
363 SkPaint restorePaint;
364 restorePaint.setImageFilter(fPaint.refImageFilter());
365 restorePaint.setBlendMode(fPaint.getBlendMode());
366
367 // Remove the restorePaint fields from our "working" paint
368 fPaint.setImageFilter(nullptr);
369 fPaint.setBlendMode(SkBlendMode::kSrcOver);
370
371 SkRect storage;
372 if (rawBounds && fPaint.canComputeFastBounds()) {
373 // Make rawBounds include all paint outsets except for those due to image filters.
374 // At this point, fPaint's image filter has been moved to 'restorePaint'.
375 SkASSERT(!fPaint.getImageFilter());
376 rawBounds = &fPaint.computeFastBounds(*rawBounds, &storage);
377 }
378
379 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &restorePaint),
380 SkCanvas::kFullLayer_SaveLayerStrategy);
381 fTempLayerForImageFilter = true;
382 }
383 }
384
~AutoLayerForImageFilter()385 ~AutoLayerForImageFilter() {
386 if (fTempLayerForImageFilter) {
387 fCanvas->internalRestore();
388 }
389 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
390 }
391
paint() const392 const SkPaint& paint() const { return fPaint; }
393
394 private:
395 SkPaint fPaint;
396 SkCanvas* fCanvas;
397 bool fTempLayerForImageFilter;
398
399 SkDEBUGCODE(int fSaveCount;)
400 };
401
402 ////////////////////////////////////////////////////////////////////////////
403
resetForNextPicture(const SkIRect & bounds)404 void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
405 this->restoreToCount(1);
406
407 // We're peering through a lot of structs here. Only at this scope do we
408 // know that the device is a SkNoPixelsDevice.
409 SkASSERT(fBaseDevice->isNoPixelsDevice());
410 static_cast<SkNoPixelsDevice*>(fBaseDevice.get())->resetForNextPicture(bounds);
411 fMCRec->reset(fBaseDevice.get());
412 fQuickRejectBounds = this->computeDeviceClipBounds();
413 }
414
init(sk_sp<SkBaseDevice> device)415 void SkCanvas::init(sk_sp<SkBaseDevice> device) {
416 // SkCanvas.h declares internal storage for the hidden struct MCRec, and this
417 // assert ensure it's sufficient. <= is used because the struct has pointer fields, so the
418 // declared size is an upper bound across architectures. When the size is smaller, more stack
419 static_assert(sizeof(MCRec) <= kMCRecSize);
420
421 if (!device) {
422 device = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeEmpty(), fProps);
423 }
424
425 // From this point on, SkCanvas will always have a device
426 SkASSERT(device);
427
428 fSaveCount = 1;
429 fMCRec = new (fMCStack.push_back()) MCRec(device.get());
430 fMarkerStack = sk_make_sp<SkMarkerStack>();
431
432 // The root device and the canvas should always have the same pixel geometry
433 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
434 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
435 device->setMarkerStack(fMarkerStack.get());
436
437 fSurfaceBase = nullptr;
438 fBaseDevice = std::move(device);
439 fScratchGlyphRunBuilder = std::make_unique<SkGlyphRunBuilder>();
440 fQuickRejectBounds = this->computeDeviceClipBounds();
441 }
442
SkCanvas()443 SkCanvas::SkCanvas()
444 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
445 , fProps()
446 {
447 inc_canvas();
448 this->init(nullptr);
449 }
450
SkCanvas(int width,int height,const SkSurfaceProps * props)451 SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
452 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
453 , fProps(SkSurfacePropsCopyOrDefault(props))
454 {
455 inc_canvas();
456 this->init(sk_make_sp<SkNoPixelsDevice>(
457 SkIRect::MakeWH(std::max(width, 0), std::max(height, 0)), fProps));
458 }
459
SkCanvas(const SkIRect & bounds)460 SkCanvas::SkCanvas(const SkIRect& bounds)
461 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
462 , fProps()
463 {
464 inc_canvas();
465
466 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
467 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
468 }
469
SkCanvas(sk_sp<SkBaseDevice> device)470 SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
471 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
472 , fProps(device->surfaceProps())
473 {
474 inc_canvas();
475
476 this->init(device);
477 }
478
SkCanvas(const SkBitmap & bitmap,const SkSurfaceProps & props)479 SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
480 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
481 , fProps(props)
482 {
483 inc_canvas();
484
485 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
486 this->init(device);
487 }
488
SkCanvas(const SkBitmap & bitmap,std::unique_ptr<SkRasterHandleAllocator> alloc,SkRasterHandleAllocator::Handle hndl)489 SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
490 SkRasterHandleAllocator::Handle hndl)
491 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
492 , fProps()
493 , fAllocator(std::move(alloc))
494 {
495 inc_canvas();
496
497 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
498 this->init(device);
499 }
500
SkCanvas(const SkBitmap & bitmap)501 SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
502
503 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
SkCanvas(const SkBitmap & bitmap,ColorBehavior)504 SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
505 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), fProps(), fAllocator(nullptr)
506 {
507 inc_canvas();
508
509 SkBitmap tmp(bitmap);
510 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
511 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
512 this->init(device);
513 }
514 #endif
515
~SkCanvas()516 SkCanvas::~SkCanvas() {
517 // free up the contents of our deque
518 this->restoreToCount(1); // restore everything but the last
519
520 this->internalRestore(); // restore the last, since we're going away
521
522 dec_canvas();
523 }
524
525 ///////////////////////////////////////////////////////////////////////////////
526
flush()527 void SkCanvas::flush() {
528 this->onFlush();
529 }
530
onFlush()531 void SkCanvas::onFlush() {
532 #if SK_SUPPORT_GPU
533 auto dContext = GrAsDirectContext(this->recordingContext());
534
535 if (dContext) {
536 dContext->flushAndSubmit();
537 }
538 #endif
539 }
540
getSurface() const541 SkSurface* SkCanvas::getSurface() const {
542 return fSurfaceBase;
543 }
544
getBaseLayerSize() const545 SkISize SkCanvas::getBaseLayerSize() const {
546 return this->baseDevice()->imageInfo().dimensions();
547 }
548
topDevice() const549 SkBaseDevice* SkCanvas::topDevice() const {
550 SkASSERT(fMCRec->fDevice);
551 return fMCRec->fDevice;
552 }
553
topDeviceSurfaceDrawContext()554 GrSurfaceDrawContext* SkCanvas::topDeviceSurfaceDrawContext() {
555 return this->topDevice()->surfaceDrawContext();
556 }
557
readPixels(const SkPixmap & pm,int x,int y)558 bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
559 return pm.addr() && this->baseDevice()->readPixels(pm, x, y);
560 }
561
readPixels(const SkImageInfo & dstInfo,void * dstP,size_t rowBytes,int x,int y)562 bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
563 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
564 }
565
readPixels(const SkBitmap & bm,int x,int y)566 bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
567 SkPixmap pm;
568 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
569 }
570
writePixels(const SkBitmap & bitmap,int x,int y)571 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
572 SkPixmap pm;
573 if (bitmap.peekPixels(&pm)) {
574 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
575 }
576 return false;
577 }
578
writePixels(const SkImageInfo & srcInfo,const void * pixels,size_t rowBytes,int x,int y)579 bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
580 int x, int y) {
581 SkBaseDevice* device = this->baseDevice();
582
583 // This check gives us an early out and prevents generation ID churn on the surface.
584 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
585 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
586 if (!srcRect.intersect({0, 0, device->width(), device->height()})) {
587 return false;
588 }
589
590 // Tell our owning surface to bump its generation ID.
591 const bool completeOverwrite =
592 srcRect.size() == SkISize::Make(device->width(), device->height());
593 this->predrawNotify(completeOverwrite);
594
595 // This can still fail, most notably in the case of a invalid color type or alpha type
596 // conversion. We could pull those checks into this function and avoid the unnecessary
597 // generation ID bump. But then we would be performing those checks twice, since they
598 // are also necessary at the bitmap/pixmap entry points.
599 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
600 }
601
602 //////////////////////////////////////////////////////////////////////////////
603
checkForDeferredSave()604 void SkCanvas::checkForDeferredSave() {
605 if (fMCRec->fDeferredSaveCount > 0) {
606 this->doSave();
607 }
608 }
609
getSaveCount() const610 int SkCanvas::getSaveCount() const {
611 #ifdef SK_DEBUG
612 int count = 0;
613 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
614 for (;;) {
615 const MCRec* rec = (const MCRec*)iter.next();
616 if (!rec) {
617 break;
618 }
619 count += 1 + rec->fDeferredSaveCount;
620 }
621 SkASSERT(count == fSaveCount);
622 #endif
623 return fSaveCount;
624 }
625
save()626 int SkCanvas::save() {
627 fSaveCount += 1;
628 fMCRec->fDeferredSaveCount += 1;
629 return this->getSaveCount() - 1; // return our prev value
630 }
631
doSave()632 void SkCanvas::doSave() {
633 this->willSave();
634
635 SkASSERT(fMCRec->fDeferredSaveCount > 0);
636 fMCRec->fDeferredSaveCount -= 1;
637 this->internalSave();
638 }
639
restore()640 void SkCanvas::restore() {
641 if (fMCRec->fDeferredSaveCount > 0) {
642 SkASSERT(fSaveCount > 1);
643 fSaveCount -= 1;
644 fMCRec->fDeferredSaveCount -= 1;
645 } else {
646 // check for underflow
647 if (fMCStack.count() > 1) {
648 this->willRestore();
649 SkASSERT(fSaveCount > 1);
650 fSaveCount -= 1;
651 this->internalRestore();
652 this->didRestore();
653 }
654 }
655 }
656
restoreToCount(int count)657 void SkCanvas::restoreToCount(int count) {
658 // safety check
659 if (count < 1) {
660 count = 1;
661 }
662
663 int n = this->getSaveCount() - count;
664 for (int i = 0; i < n; ++i) {
665 this->restore();
666 }
667 }
668
internalSave()669 void SkCanvas::internalSave() {
670 fMCRec = new (fMCStack.push_back()) MCRec(*fMCRec);
671
672 this->topDevice()->save();
673 }
674
clipRectBounds(const SkRect * bounds,SkIRect * intersection,const SkImageFilter * imageFilter)675 bool SkCanvas::clipRectBounds(const SkRect* bounds, SkIRect* intersection,
676 const SkImageFilter* imageFilter) {
677 // clipRectBounds() is called to determine the input layer size needed for a given image filter.
678 // The coordinate space of the rectangle passed to filterBounds(kReverse) is meant to be in the
679 // filtering layer space. Here, 'clipBounds' is always in the true device space. When an image
680 // filter does not require a decomposed CTM matrix, the filter space and device space are the
681 // same. When it has been decomposed, we want the original image filter node to process the
682 // bounds in the layer space represented by the decomposed scale matrix. 'imageFilter' is no
683 // longer the original filter, but has the remainder matrix baked into it, and passing in the
684 // the true device clip bounds ensures that the matrix image filter provides a layer clip bounds
685 // to the original filter node (barring inflation from consecutive calls to mapRect). While
686 // initially counter-intuitive given the apparent inconsistency of coordinate spaces, always
687 // passing getDeviceClipBounds() to 'imageFilter' is correct.
688 // FIXME (michaelludwig) - When the remainder matrix is instead applied as a final draw, it will
689 // be important to more accurately calculate the clip bounds in the layer space for the original
690 // image filter (similar to how matrix image filter does it, but ideally without the inflation).
691 SkIRect clipBounds = this->getDeviceClipBounds();
692 if (clipBounds.isEmpty()) {
693 return false;
694 }
695
696 const SkMatrix& ctm = fMCRec->fMatrix.asM33(); // this->getTotalMatrix()
697
698 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
699 // If the image filter DAG affects transparent black then we will need to render
700 // out to the clip bounds
701 bounds = nullptr;
702 }
703
704 SkIRect inputSaveLayerBounds;
705 if (bounds) {
706 SkRect r;
707 ctm.mapRect(&r, *bounds);
708 r.roundOut(&inputSaveLayerBounds);
709 } else { // no user bounds, so just use the clip
710 inputSaveLayerBounds = clipBounds;
711 }
712
713 if (imageFilter) {
714 // expand the clip bounds by the image filter DAG to include extra content that might
715 // be required by the image filters.
716 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
717 SkImageFilter::kReverse_MapDirection,
718 &inputSaveLayerBounds);
719 }
720
721 SkIRect clippedSaveLayerBounds;
722 if (bounds) {
723 // For better or for worse, user bounds currently act as a hard clip on the layer's
724 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
725 clippedSaveLayerBounds = inputSaveLayerBounds;
726 } else {
727 // If there are no user bounds, we don't want to artificially restrict the resulting
728 // layer bounds, so allow the expanded clip bounds free reign.
729 clippedSaveLayerBounds = clipBounds;
730 }
731
732 // early exit if the layer's bounds are clipped out
733 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
734 return false;
735 }
736 SkASSERT(!clippedSaveLayerBounds.isEmpty());
737
738 if (intersection) {
739 *intersection = clippedSaveLayerBounds;
740 }
741
742 return true;
743 }
744
saveLayer(const SkRect * bounds,const SkPaint * paint)745 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
746 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
747 }
748
saveLayer(const SaveLayerRec & rec)749 int SkCanvas::saveLayer(const SaveLayerRec& rec) {
750 TRACE_EVENT0("skia", TRACE_FUNC);
751 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
752 // no need for the layer (or any of the draws until the matching restore()
753 this->save();
754 this->clipRect({0,0,0,0});
755 } else {
756 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
757 fSaveCount += 1;
758 this->internalSaveLayer(rec, strategy);
759 }
760 return this->getSaveCount() - 1;
761 }
762
only_axis_aligned_saveBehind(const SkRect * bounds)763 int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
764 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
765 // Assuming clips never expand, if the request bounds is outside of the current clip
766 // there is no need to copy/restore the area, so just devolve back to a regular save.
767 this->save();
768 } else {
769 bool doTheWork = this->onDoSaveBehind(bounds);
770 fSaveCount += 1;
771 this->internalSave();
772 if (doTheWork) {
773 this->internalSaveBehind(bounds);
774 }
775 }
776 return this->getSaveCount() - 1;
777 }
778
DrawDeviceWithFilter(SkBaseDevice * src,const SkImageFilter * filter,SkBaseDevice * dst,const SkIPoint & dstOrigin,const SkMatrix & ctm)779 void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
780 SkBaseDevice* dst, const SkIPoint& dstOrigin,
781 const SkMatrix& ctm) {
782 // The local bounds of the src device; all the bounds passed to snapSpecial must be intersected
783 // with this rect.
784 const SkIRect srcDevRect = SkIRect::MakeWH(src->width(), src->height());
785 // TODO(michaelludwig) - Update this function to use the relative transforms between src and
786 // dst; for now, since devices never have complex transforms, we can keep using getOrigin().
787 if (!filter) {
788 // All non-filtered devices are currently axis aligned, so they only differ by their origin.
789 // This means that we only have to copy a dst-sized block of pixels out of src and translate
790 // it to the matching position relative to dst's origin.
791 SkIRect snapBounds = SkIRect::MakeXYWH(dstOrigin.x() - src->getOrigin().x(),
792 dstOrigin.y() - src->getOrigin().y(),
793 dst->width(), dst->height());
794 if (!snapBounds.intersect(srcDevRect)) {
795 return;
796 }
797
798 auto special = src->snapSpecial(snapBounds);
799 if (special) {
800 // The image is drawn at 1-1 scale with integer translation, so no filtering is needed.
801 dst->drawSpecial(special.get(), SkMatrix::I(), SkSamplingOptions(), SkPaint());
802 }
803 return;
804 }
805
806 // First decompose the ctm into a post-filter transform and a filter matrix that is supported
807 // by the backdrop filter.
808 SkMatrix toRoot, layerMatrix;
809 SkSize scale;
810 if (ctm.isScaleTranslate() || as_IFB(filter)->canHandleComplexCTM()) {
811 toRoot = SkMatrix::I();
812 layerMatrix = ctm;
813 } else if (ctm.decomposeScale(&scale, &toRoot)) {
814 layerMatrix = SkMatrix::Scale(scale.fWidth, scale.fHeight);
815 } else {
816 // Perspective, for now, do no scaling of the layer itself.
817 // TODO (michaelludwig) - perhaps it'd be better to explore a heuristic scale pulled from
818 // the matrix, e.g. based on the midpoint of the near/far planes?
819 toRoot = ctm;
820 layerMatrix = SkMatrix::I();
821 }
822
823 // We have to map the dst bounds from the root space into the layer space where filtering will
824 // occur. If we knew the input bounds of the content that defined the original dst bounds, we
825 // could map that forward by layerMatrix and have tighter bounds, but toRoot^-1 * dst bounds
826 // is a safe, conservative estimate.
827 SkMatrix fromRoot;
828 if (!toRoot.invert(&fromRoot)) {
829 return;
830 }
831
832 // This represents what the backdrop filter needs to produce in the layer space, and is sized
833 // such that drawing it into dst with the toRoot transform will cover the actual dst device.
834 SkIRect layerTargetBounds = fromRoot.mapRect(
835 SkRect::MakeXYWH(dstOrigin.x(), dstOrigin.y(), dst->width(), dst->height())).roundOut();
836 // While layerTargetBounds is what needs to be output by the filter, the filtering process may
837 // require some extra input pixels.
838 SkIRect layerInputBounds = filter->filterBounds(
839 layerTargetBounds, layerMatrix, SkImageFilter::kReverse_MapDirection,
840 &layerTargetBounds);
841
842 // Map the required input into the root space, then make relative to the src device. This will
843 // be the conservative contents required to fill a layerInputBounds-sized surface with the
844 // backdrop content (transformed back into the layer space using fromRoot).
845 SkIRect backdropBounds = toRoot.mapRect(SkRect::Make(layerInputBounds)).roundOut();
846 backdropBounds.offset(-src->getOrigin().x(), -src->getOrigin().y());
847 if (!backdropBounds.intersect(srcDevRect)) {
848 return;
849 }
850
851 auto special = src->snapSpecial(backdropBounds);
852 if (!special) {
853 return;
854 }
855
856 SkColorType colorType = src->imageInfo().colorType();
857 if (colorType == kUnknown_SkColorType) {
858 colorType = kRGBA_8888_SkColorType;
859 }
860 SkColorSpace* colorSpace = src->imageInfo().colorSpace();
861
862 SkPaint p;
863 SkSamplingOptions sampling;
864
865 if (!toRoot.isIdentity()) {
866 // Drawing the temporary and final filtered image requires a higher filter quality if the
867 // 'toRoot' transformation is not identity, in order to minimize the impact on already
868 // rendered edges/content.
869 // TODO (michaelludwig) - Explore reducing this quality, identify visual tradeoffs
870 sampling = SkSamplingOptions({1.0f/3, 1.0f/3});
871
872 // The snapped backdrop content needs to be transformed by fromRoot into the layer space,
873 // and stored in a temporary surface, which is then used as the input to the actual filter.
874 auto tmpSurface = special->makeSurface(colorType, colorSpace, layerInputBounds.size(),
875 kPremul_SkAlphaType, dst->surfaceProps());
876 if (!tmpSurface) {
877 return;
878 }
879
880 auto tmpCanvas = tmpSurface->getCanvas();
881 tmpCanvas->clear(SK_ColorTRANSPARENT);
882 // Reading in reverse, this takes the backdrop bounds from src device space into the root
883 // space, then maps from root space into the layer space, then maps it so the input layer's
884 // top left corner is (0, 0). This transformation automatically accounts for any cropping
885 // performed on backdropBounds.
886 tmpCanvas->translate(-layerInputBounds.fLeft, -layerInputBounds.fTop);
887 tmpCanvas->concat(fromRoot);
888 tmpCanvas->translate(src->getOrigin().x(), src->getOrigin().y());
889
890 tmpCanvas->drawImageRect(special->asImage().get(), SkRect::Make(special->subset()),
891 SkRect::Make(backdropBounds), sampling, &p,
892 kStrict_SrcRectConstraint);
893 special = tmpSurface->makeImageSnapshot();
894 } else {
895 // Since there is no extra transform that was done, update the input bounds to reflect
896 // cropping of the snapped backdrop image. In this case toRoot = I, so layerInputBounds
897 // was equal to backdropBounds before it was made relative to the src device and cropped.
898 // When we use the original snapped image directly, just map the update backdrop bounds
899 // back into the shared layer space
900 layerInputBounds = backdropBounds;
901 layerInputBounds.offset(src->getOrigin().x(), src->getOrigin().y());
902
903 // Similar to the unfiltered case above, when toRoot is the identity, then the final
904 // draw will be 1-1 so there is no need to increase filter quality.
905 sampling = SkSamplingOptions();
906 }
907
908 // Now evaluate the filter on 'special', which contains the backdrop content mapped back into
909 // layer space. This has to further offset everything so that filter evaluation thinks the
910 // source image's top left corner is (0, 0).
911 // TODO (michaelludwig) - Once image filters are robust to non-(0,0) image origins for inputs,
912 // this can be simplified.
913 layerTargetBounds.offset(-layerInputBounds.fLeft, -layerInputBounds.fTop);
914 SkMatrix filterCTM = layerMatrix;
915 filterCTM.postTranslate(-layerInputBounds.fLeft, -layerInputBounds.fTop);
916 skif::Context ctx(filterCTM, layerTargetBounds, nullptr, colorType, colorSpace, special.get());
917
918 SkIPoint offset;
919 special = as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset);
920 if (special) {
921 // Draw the filtered backdrop content into the dst device. We add layerInputBounds origin
922 // to offset because the original value in 'offset' was relative to 'filterCTM'. 'filterCTM'
923 // had subtracted the layerInputBounds origin, so adding that back makes 'offset' relative
924 // to 'layerMatrix' (what we need it to be when drawing the image by 'toRoot').
925 offset += layerInputBounds.topLeft();
926
927 // Manually setting the device's CTM requires accounting for the device's origin.
928 // TODO (michaelludwig) - This could be simpler if the dst device had its origin configured
929 // before filtering the backdrop device and we use skif::Mapping instead.
930 SkMatrix dstCTM = toRoot;
931 dstCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
932 dstCTM.preTranslate(offset.fX, offset.fY);
933 dst->drawSpecial(special.get(), dstCTM, sampling, p);
934 }
935 }
936
make_layer_info(const SkImageInfo & prev,int w,int h,const SkPaint * paint)937 static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
938 SkColorType ct = prev.colorType();
939 if (prev.bytesPerPixel() <= 4 &&
940 prev.colorType() != kRGBA_8888_SkColorType &&
941 prev.colorType() != kBGRA_8888_SkColorType) {
942 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
943 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
944 ct = kN32_SkColorType;
945 }
946 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
947 }
948
internalSaveLayer(const SaveLayerRec & rec,SaveLayerStrategy strategy)949 void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
950 TRACE_EVENT0("skia", TRACE_FUNC);
951 const SkRect* bounds = rec.fBounds;
952 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
953
954 SkTCopyOnFirstWrite<SkPaint> paint(rec.fPaint);
955 // saveLayer ignores mask filters, so force it to null
956 if (paint.get() && paint->getMaskFilter()) {
957 paint.writable()->setMaskFilter(nullptr);
958 }
959
960 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
961 // regardless of any hint-rect from the caller. skbug.com/8783
962 if (rec.fBackdrop) {
963 bounds = nullptr;
964 }
965
966 SkImageFilter* imageFilter = paint.get() ? paint->getImageFilter() : nullptr;
967 SkM44 stashedMatrix = fMCRec->fMatrix;
968
969 /*
970 * Many ImageFilters (so far) do not (on their own) correctly handle matrices (CTM) that
971 * contain rotation/skew/etc. We rely on applyCTM to create a new image filter DAG as needed to
972 * accommodate this, but it requires update the CTM we use when drawing into the layer.
973 *
974 * 1. Stash off the current CTM
975 * 2. Apply the CTM to imagefilter, which decomposes it into simple and complex transforms
976 * if necessary.
977 * 3. Wack the CTM to be the remaining scale matrix and use the modified imagefilter, which
978 * is a MatrixImageFilter that contains the complex matrix.
979 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
980 * 5. During restore, the MatrixImageFilter automatically applies complex stage to the output
981 * of the original imagefilter, and draw that (via drawSprite)
982 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
983 *
984 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
985 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
986 */
987 if (imageFilter) {
988 SkMatrix modifiedCTM;
989 sk_sp<SkImageFilter> modifiedFilter = as_IFB(imageFilter)->applyCTM(stashedMatrix.asM33(),
990 &modifiedCTM);
991 if (as_IFB(modifiedFilter)->uniqueID() != as_IFB(imageFilter)->uniqueID()) {
992 // The original filter couldn't support the CTM entirely
993 SkASSERT(modifiedCTM.isScaleTranslate() || as_IFB(imageFilter)->canHandleComplexCTM());
994 this->internalSetMatrix(SkM44(modifiedCTM));
995 imageFilter = modifiedFilter.get();
996 paint.writable()->setImageFilter(std::move(modifiedFilter));
997 }
998 // Else the filter didn't change, so modifiedCTM == stashedMatrix and there's nothing
999 // left to do since the stack already has that as the CTM.
1000 }
1001
1002 // do this before we create the layer. We don't call the public save() since
1003 // that would invoke a possibly overridden virtual
1004 this->internalSave();
1005
1006 SkIRect ir;
1007 if (!this->clipRectBounds(bounds, &ir, imageFilter)) {
1008 // No layer to draw
1009 ir.setEmpty();
1010 strategy = kNoLayer_SaveLayerStrategy;
1011 }
1012
1013 SkBaseDevice* priorDevice = this->topDevice();
1014 sk_sp<SkBaseDevice> newDevice;
1015 if (strategy == kFullLayer_SaveLayerStrategy) {
1016 SkASSERT(!ir.isEmpty());
1017 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(),
1018 paint);
1019 if (rec.fSaveLayerFlags & kF16ColorType) {
1020 info = info.makeColorType(kRGBA_F16_SkColorType);
1021 }
1022 SkASSERT(info.alphaType() != kOpaque_SkAlphaType);
1023
1024 SkPixelGeometry geo = saveLayerFlags & kPreserveLCDText_SaveLayerFlag
1025 ? fProps.pixelGeometry()
1026 : kUnknown_SkPixelGeometry;
1027 const bool trackCoverage =
1028 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
1029 const auto createInfo = SkBaseDevice::CreateInfo(info,
1030 geo,
1031 SkBaseDevice::kNever_TileUsage,
1032 trackCoverage,
1033 fAllocator.get());
1034 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1035 }
1036
1037 bool initBackdrop = (rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop;
1038 if (!newDevice) {
1039 // Either we weren't meant to allocate a full layer, or the full layer creation failed.
1040 // Using an explicit NoPixelsDevice lets us reflect what the layer state would have been
1041 // on success (or kFull_LayerStrategy) while squashing draw calls that target something that
1042 // doesn't exist.
1043 newDevice = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeWH(ir.width(), ir.height()), fProps,
1044 this->imageInfo().refColorSpace());
1045 initBackdrop = false;
1046 }
1047
1048 newDevice->setMarkerStack(fMarkerStack.get());
1049
1050 if (initBackdrop) {
1051 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
1052 fMCRec->fMatrix.asM33());
1053 }
1054
1055 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1056 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1057
1058 fMCRec->newLayer(std::move(newDevice), paint, stashedMatrix);
1059
1060 fQuickRejectBounds = this->computeDeviceClipBounds();
1061 }
1062
saveLayerAlpha(const SkRect * bounds,U8CPU alpha)1063 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1064 if (0xFF == alpha) {
1065 return this->saveLayer(bounds, nullptr);
1066 } else {
1067 SkPaint tmpPaint;
1068 tmpPaint.setAlpha(alpha);
1069 return this->saveLayer(bounds, &tmpPaint);
1070 }
1071 }
1072
internalSaveBehind(const SkRect * localBounds)1073 void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1074 SkBaseDevice* device = this->topDevice();
1075
1076 // Map the local bounds into the top device's coordinate space (this is not
1077 // necessarily the full global CTM transform).
1078 SkIRect devBounds;
1079 if (localBounds) {
1080 SkRect tmp;
1081 device->localToDevice().mapRect(&tmp, *localBounds);
1082 if (!devBounds.intersect(tmp.round(), device->devClipBounds())) {
1083 devBounds.setEmpty();
1084 }
1085 } else {
1086 devBounds = device->devClipBounds();
1087 }
1088 if (devBounds.isEmpty()) {
1089 return;
1090 }
1091
1092 // This is getting the special image from the current device, which is then drawn into (both by
1093 // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its
1094 // own device, we need to explicitly copy the back image contents so that its original content
1095 // is available when we splat it back later during restore.
1096 auto backImage = device->snapSpecial(devBounds, /* copy */ true);
1097 if (!backImage) {
1098 return;
1099 }
1100
1101 // we really need the save, so we can wack the fMCRec
1102 this->checkForDeferredSave();
1103
1104 fMCRec->fBackImage =
1105 std::make_unique<BackImage>(BackImage{std::move(backImage), devBounds.topLeft()});
1106
1107 SkPaint paint;
1108 paint.setBlendMode(SkBlendMode::kClear);
1109 this->drawClippedToSaveBehind(paint);
1110 }
1111
internalRestore()1112 void SkCanvas::internalRestore() {
1113 SkASSERT(fMCStack.count() != 0);
1114
1115 // now detach these from fMCRec so we can pop(). Gets freed after its drawn
1116 std::unique_ptr<Layer> layer = std::move(fMCRec->fLayer);
1117 std::unique_ptr<BackImage> backImage = std::move(fMCRec->fBackImage);
1118
1119 fMarkerStack->restore(fMCRec);
1120
1121 // now do the normal restore()
1122 fMCRec->~MCRec(); // balanced in save()
1123 fMCStack.pop_back();
1124 fMCRec = (MCRec*) fMCStack.back();
1125
1126 if (!fMCRec) {
1127 // This was the last record, restored during the destruction of the SkCanvas
1128 return;
1129 }
1130
1131 this->topDevice()->restore(fMCRec->fMatrix);
1132
1133 if (backImage) {
1134 SkPaint paint;
1135 paint.setBlendMode(SkBlendMode::kDstOver);
1136 this->topDevice()->drawSpecial(backImage->fImage.get(),
1137 SkMatrix::Translate(backImage->fLoc),
1138 SkSamplingOptions(),
1139 paint);
1140 }
1141
1142 // Draw the layer's device contents into the now-current older device. We can't call public
1143 // draw functions since we don't want to record them.
1144 if (layer) {
1145 layer->fDevice->setImmutable();
1146
1147 SkSamplingOptions sampling; // todo: may need more than NN in the future
1148
1149 // At this point, 'layer' has been removed from the device stack, so the devices that
1150 // internalDrawDevice sees are the destinations that 'layer' is drawn into.
1151 this->internalDrawDevice(layer->fDevice.get(), sampling, layer->fPaint.get());
1152 // restore what we smashed in internalSaveLayer
1153 this->internalSetMatrix(SkM44(layer->fStashedMatrix));
1154 }
1155
1156 // Update the quick-reject bounds in case the restore changed the top device or the
1157 // removed save record had included modifications to the clip stack.
1158 fQuickRejectBounds = this->computeDeviceClipBounds();
1159 this->validateClip();
1160 }
1161
makeSurface(const SkImageInfo & info,const SkSurfaceProps * props)1162 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1163 if (nullptr == props) {
1164 props = &fProps;
1165 }
1166 return this->onNewSurface(info, *props);
1167 }
1168
onNewSurface(const SkImageInfo & info,const SkSurfaceProps & props)1169 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1170 return this->baseDevice()->makeSurface(info, props);
1171 }
1172
imageInfo() const1173 SkImageInfo SkCanvas::imageInfo() const {
1174 return this->onImageInfo();
1175 }
1176
onImageInfo() const1177 SkImageInfo SkCanvas::onImageInfo() const {
1178 return this->baseDevice()->imageInfo();
1179 }
1180
getProps(SkSurfaceProps * props) const1181 bool SkCanvas::getProps(SkSurfaceProps* props) const {
1182 return this->onGetProps(props);
1183 }
1184
onGetProps(SkSurfaceProps * props) const1185 bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
1186 if (props) {
1187 *props = fProps;
1188 }
1189 return true;
1190 }
1191
peekPixels(SkPixmap * pmap)1192 bool SkCanvas::peekPixels(SkPixmap* pmap) {
1193 return this->onPeekPixels(pmap);
1194 }
1195
onPeekPixels(SkPixmap * pmap)1196 bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
1197 return this->baseDevice()->peekPixels(pmap);
1198 }
1199
accessTopLayerPixels(SkImageInfo * info,size_t * rowBytes,SkIPoint * origin)1200 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1201 SkPixmap pmap;
1202 if (!this->onAccessTopLayerPixels(&pmap)) {
1203 return nullptr;
1204 }
1205 if (info) {
1206 *info = pmap.info();
1207 }
1208 if (rowBytes) {
1209 *rowBytes = pmap.rowBytes();
1210 }
1211 if (origin) {
1212 // If the caller requested the origin, they presumably are expecting the returned pixels to
1213 // be axis-aligned with the root canvas. If the top level device isn't axis aligned, that's
1214 // not the case. Until we update accessTopLayerPixels() to accept a coord space matrix
1215 // instead of an origin, just don't expose the pixels in that case. Note that this means
1216 // that layers with complex coordinate spaces can still report their pixels if the caller
1217 // does not ask for the origin (e.g. just to dump its output to a file, etc).
1218 if (this->topDevice()->isPixelAlignedToGlobal()) {
1219 *origin = this->topDevice()->getOrigin();
1220 } else {
1221 return nullptr;
1222 }
1223 }
1224 return pmap.writable_addr();
1225 }
1226
onAccessTopLayerPixels(SkPixmap * pmap)1227 bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
1228 return this->topDevice()->accessPixels(pmap);
1229 }
1230
1231 /////////////////////////////////////////////////////////////////////////////
1232
1233 // In our current design/features, we should never have a layer (src) in a different colorspace
1234 // than its parent (dst), so we assert that here. This is called out from other asserts, in case
1235 // we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1236 // colorspace.
check_drawdevice_colorspaces(SkColorSpace * src,SkColorSpace * dst)1237 static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1238 SkASSERT(src == dst);
1239 }
1240
internalDrawDevice(SkBaseDevice * srcDev,const SkSamplingOptions & sampling,const SkPaint * paint)1241 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, const SkSamplingOptions& sampling,
1242 const SkPaint* paint) {
1243 // Nothing to draw, and we know snapSpecial() would have returned null and 'srcDev' likely
1244 // wasn't returned from onCreateDevice() so isn't allowed to be passed to drawDevice()
1245 if (srcDev->isNoPixelsDevice()) {
1246 return;
1247 }
1248
1249 SkPaint noFilterPaint = paint ? *paint : SkPaint{};
1250 sk_sp<SkImageFilter> filter;
1251 if (noFilterPaint.getImageFilter() && !image_to_color_filter(&noFilterPaint)) {
1252 filter = noFilterPaint.refImageFilter();
1253 noFilterPaint.setImageFilter(nullptr);
1254 }
1255 SkASSERT(!noFilterPaint.getImageFilter());
1256
1257 SkBaseDevice* dstDev = this->topDevice();
1258 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1259 srcDev->imageInfo().colorSpace());
1260
1261 this->predrawNotify();
1262 if (!filter) {
1263 // Can draw the src device's buffer w/o any extra image filter evaluation
1264 // (although this draw may include color filter processing extracted from the IF DAG).
1265 dstDev->drawDevice(srcDev, sampling, noFilterPaint);
1266 } else {
1267 // Use the whole device buffer, presumably it was sized appropriately to match the
1268 // desired output size of the destination when the layer was first saved.
1269 sk_sp<SkSpecialImage> srcBuffer = srcDev->snapSpecial();
1270 if (!srcBuffer) {
1271 return;
1272 }
1273
1274 // Evaluate the image filter DAG on the src device's buffer. The filter processes an
1275 // image in the src's device space. However, the filter parameters need to respect the
1276 // dst's local matrix (this reflects the CTM that was set when the layer was first
1277 // saved). We can achieve this by concatenating the dst's local-to-device matrix with
1278 // the relative transform from dst to src. Then the final result is drawn to dst using
1279 // the relative transform from src to dst.
1280 SkMatrix srcToDst = srcDev->getRelativeTransform(*dstDev);
1281 SkMatrix dstToSrc = dstDev->getRelativeTransform(*srcDev);
1282 skif::Mapping mapping(srcToDst, SkMatrix::Concat(dstToSrc, dstDev->localToDevice()));
1283 dstDev->drawFilteredImage(mapping, srcBuffer.get(), filter.get(), sampling, noFilterPaint);
1284 }
1285 }
1286
1287 /////////////////////////////////////////////////////////////////////////////
1288
translate(SkScalar dx,SkScalar dy)1289 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1290 if (dx || dy) {
1291 this->checkForDeferredSave();
1292 fMCRec->fMatrix.preTranslate(dx, dy);
1293
1294 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1295
1296 this->didTranslate(dx,dy);
1297 }
1298 }
1299
scale(SkScalar sx,SkScalar sy)1300 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1301 if (sx != 1 || sy != 1) {
1302 this->checkForDeferredSave();
1303 fMCRec->fMatrix.preScale(sx, sy);
1304
1305 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1306
1307 this->didScale(sx, sy);
1308 }
1309 }
1310
rotate(SkScalar degrees)1311 void SkCanvas::rotate(SkScalar degrees) {
1312 SkMatrix m;
1313 m.setRotate(degrees);
1314 this->concat(m);
1315 }
1316
rotate(SkScalar degrees,SkScalar px,SkScalar py)1317 void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1318 SkMatrix m;
1319 m.setRotate(degrees, px, py);
1320 this->concat(m);
1321 }
1322
skew(SkScalar sx,SkScalar sy)1323 void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1324 SkMatrix m;
1325 m.setSkew(sx, sy);
1326 this->concat(m);
1327 }
1328
concat(const SkMatrix & matrix)1329 void SkCanvas::concat(const SkMatrix& matrix) {
1330 if (matrix.isIdentity()) {
1331 return;
1332 }
1333 this->concat(SkM44(matrix));
1334 }
1335
internalConcat44(const SkM44 & m)1336 void SkCanvas::internalConcat44(const SkM44& m) {
1337 this->checkForDeferredSave();
1338
1339 fMCRec->fMatrix.preConcat(m);
1340
1341 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1342 }
1343
concat(const SkM44 & m)1344 void SkCanvas::concat(const SkM44& m) {
1345 this->internalConcat44(m);
1346 // notify subclasses
1347 this->didConcat44(m);
1348 }
1349
internalSetMatrix(const SkM44 & m)1350 void SkCanvas::internalSetMatrix(const SkM44& m) {
1351 fMCRec->fMatrix = m;
1352
1353 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1354 }
1355
setMatrix(const SkMatrix & matrix)1356 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1357 this->setMatrix(SkM44(matrix));
1358 }
1359
setMatrix(const SkM44 & m)1360 void SkCanvas::setMatrix(const SkM44& m) {
1361 this->checkForDeferredSave();
1362 this->internalSetMatrix(m);
1363 this->didSetM44(m);
1364 }
1365
resetMatrix()1366 void SkCanvas::resetMatrix() {
1367 this->setMatrix(SkM44());
1368 }
1369
markCTM(const char * name)1370 void SkCanvas::markCTM(const char* name) {
1371 if (SkCanvasPriv::ValidateMarker(name)) {
1372 fMarkerStack->setMarker(SkOpts::hash_fn(name, strlen(name), 0),
1373 this->getLocalToDevice(), fMCRec);
1374 this->onMarkCTM(name);
1375 }
1376 }
1377
findMarkedCTM(const char * name,SkM44 * mx) const1378 bool SkCanvas::findMarkedCTM(const char* name, SkM44* mx) const {
1379 return SkCanvasPriv::ValidateMarker(name) &&
1380 fMarkerStack->findMarker(SkOpts::hash_fn(name, strlen(name), 0), mx);
1381 }
1382
1383 //////////////////////////////////////////////////////////////////////////////
1384
clipRect(const SkRect & rect,SkClipOp op,bool doAA)1385 void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
1386 if (!rect.isFinite()) {
1387 return;
1388 }
1389 this->checkForDeferredSave();
1390 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1391 this->onClipRect(rect.makeSorted(), op, edgeStyle);
1392 }
1393
onClipRect(const SkRect & rect,SkClipOp op,ClipEdgeStyle edgeStyle)1394 void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1395 SkASSERT(rect.isSorted());
1396 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1397
1398 AutoUpdateQRBounds aqr(this);
1399 this->topDevice()->clipRect(rect, op, isAA);
1400 }
1401
androidFramework_setDeviceClipRestriction(const SkIRect & rect)1402 void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1403 fClipRestrictionRect = rect;
1404 if (!fClipRestrictionRect.isEmpty()) {
1405 // we only resolve deferred saves when we're setting the restriction, not when we're
1406 // removing it (i.e. rect is empty).
1407 this->checkForDeferredSave();
1408 }
1409
1410 AutoUpdateQRBounds aqr(this);
1411 this->topDevice()->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1412 }
1413
androidFramework_replaceClip(const SkIRect & rect)1414 void SkCanvas::androidFramework_replaceClip(const SkIRect& rect) {
1415 this->checkForDeferredSave();
1416
1417 AutoUpdateQRBounds aqr(this);
1418 this->topDevice()->replaceClip(rect);
1419 }
1420
clipRRect(const SkRRect & rrect,SkClipOp op,bool doAA)1421 void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
1422 this->checkForDeferredSave();
1423 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1424 if (rrect.isRect()) {
1425 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1426 } else {
1427 this->onClipRRect(rrect, op, edgeStyle);
1428 }
1429 }
1430
onClipRRect(const SkRRect & rrect,SkClipOp op,ClipEdgeStyle edgeStyle)1431 void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1432 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1433
1434 AutoUpdateQRBounds aqr(this);
1435 this->topDevice()->clipRRect(rrect, op, isAA);
1436 }
1437
clipPath(const SkPath & path,SkClipOp op,bool doAA)1438 void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
1439 this->checkForDeferredSave();
1440 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1441
1442 if (!path.isInverseFillType() && fMCRec->fMatrix.asM33().rectStaysRect()) {
1443 SkRect r;
1444 if (path.isRect(&r)) {
1445 this->onClipRect(r, op, edgeStyle);
1446 return;
1447 }
1448 SkRRect rrect;
1449 if (path.isOval(&r)) {
1450 rrect.setOval(r);
1451 this->onClipRRect(rrect, op, edgeStyle);
1452 return;
1453 }
1454 if (path.isRRect(&rrect)) {
1455 this->onClipRRect(rrect, op, edgeStyle);
1456 return;
1457 }
1458 }
1459
1460 this->onClipPath(path, op, edgeStyle);
1461 }
1462
onClipPath(const SkPath & path,SkClipOp op,ClipEdgeStyle edgeStyle)1463 void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
1464 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1465
1466 AutoUpdateQRBounds aqr(this);
1467 this->topDevice()->clipPath(path, op, isAA);
1468 }
1469
clipShader(sk_sp<SkShader> sh,SkClipOp op)1470 void SkCanvas::clipShader(sk_sp<SkShader> sh, SkClipOp op) {
1471 if (sh) {
1472 if (sh->isOpaque()) {
1473 if (op == SkClipOp::kIntersect) {
1474 // we don't occlude anything, so skip this call
1475 } else {
1476 SkASSERT(op == SkClipOp::kDifference);
1477 // we occlude everything, so set the clip to empty
1478 this->clipRect({0,0,0,0});
1479 }
1480 } else {
1481 this->checkForDeferredSave();
1482 this->onClipShader(std::move(sh), op);
1483 }
1484 }
1485 }
1486
onClipShader(sk_sp<SkShader> sh,SkClipOp op)1487 void SkCanvas::onClipShader(sk_sp<SkShader> sh, SkClipOp op) {
1488 AutoUpdateQRBounds aqr(this);
1489 this->topDevice()->clipShader(sh, op);
1490 }
1491
clipRegion(const SkRegion & rgn,SkClipOp op)1492 void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
1493 this->checkForDeferredSave();
1494 this->onClipRegion(rgn, op);
1495 }
1496
onClipRegion(const SkRegion & rgn,SkClipOp op)1497 void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
1498 AutoUpdateQRBounds aqr(this);
1499 this->topDevice()->clipRegion(rgn, op);
1500 }
1501
validateClip() const1502 void SkCanvas::validateClip() const {
1503 #ifdef SK_DEBUG
1504 SkRect tmp = this->computeDeviceClipBounds();
1505 if (this->isClipEmpty()) {
1506 SkASSERT(fQuickRejectBounds.isEmpty());
1507 } else {
1508 SkASSERT(tmp == fQuickRejectBounds);
1509 }
1510 #endif
1511 }
1512
androidFramework_isClipAA() const1513 bool SkCanvas::androidFramework_isClipAA() const {
1514 return this->topDevice()->onClipIsAA();
1515 }
1516
temporary_internal_getRgnClip(SkRegion * rgn)1517 void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1518 rgn->setEmpty();
1519 SkBaseDevice* device = this->topDevice();
1520 if (device && device->isPixelAlignedToGlobal()) {
1521 device->onAsRgnClip(rgn);
1522 SkIPoint origin = device->getOrigin();
1523 if (origin.x() | origin.y()) {
1524 rgn->translate(origin.x(), origin.y());
1525 }
1526 }
1527 }
1528
1529 ///////////////////////////////////////////////////////////////////////////////
1530
isClipEmpty() const1531 bool SkCanvas::isClipEmpty() const {
1532 return this->topDevice()->onGetClipType() == SkBaseDevice::ClipType::kEmpty;
1533 }
1534
isClipRect() const1535 bool SkCanvas::isClipRect() const {
1536 return this->topDevice()->onGetClipType() == SkBaseDevice::ClipType::kRect;
1537 }
1538
quickReject(const SkRect & src) const1539 bool SkCanvas::quickReject(const SkRect& src) const {
1540 #ifdef SK_DEBUG
1541 // Verify that fQuickRejectBounds are set properly.
1542 this->validateClip();
1543 #endif
1544
1545 SkRect devRect = SkMatrixPriv::MapRect(fMCRec->fMatrix, src);
1546 return !devRect.isFinite() || !devRect.intersects(fQuickRejectBounds);
1547 }
1548
quickReject(const SkPath & path) const1549 bool SkCanvas::quickReject(const SkPath& path) const {
1550 return path.isEmpty() || this->quickReject(path.getBounds());
1551 }
1552
internalQuickReject(const SkRect & bounds,const SkPaint & paint,const SkMatrix * matrix)1553 bool SkCanvas::internalQuickReject(const SkRect& bounds, const SkPaint& paint,
1554 const SkMatrix* matrix) {
1555 if (!bounds.isFinite() || paint.nothingToDraw()) {
1556 return true;
1557 }
1558
1559 if (paint.canComputeFastBounds()) {
1560 SkRect tmp = matrix ? matrix->mapRect(bounds) : bounds;
1561 return this->quickReject(paint.computeFastBounds(tmp, &tmp));
1562 }
1563
1564 return false;
1565 }
1566
1567
getLocalClipBounds() const1568 SkRect SkCanvas::getLocalClipBounds() const {
1569 SkIRect ibounds = this->getDeviceClipBounds();
1570 if (ibounds.isEmpty()) {
1571 return SkRect::MakeEmpty();
1572 }
1573
1574 SkMatrix inverse;
1575 // if we can't invert the CTM, we can't return local clip bounds
1576 if (!fMCRec->fMatrix.asM33().invert(&inverse)) {
1577 return SkRect::MakeEmpty();
1578 }
1579
1580 SkRect bounds;
1581 // adjust it outwards in case we are antialiasing
1582 const int margin = 1;
1583
1584 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
1585 inverse.mapRect(&bounds, r);
1586 return bounds;
1587 }
1588
getDeviceClipBounds() const1589 SkIRect SkCanvas::getDeviceClipBounds() const {
1590 return this->computeDeviceClipBounds(/*outsetForAA=*/false).roundOut();
1591 }
1592
computeDeviceClipBounds(bool outsetForAA) const1593 SkRect SkCanvas::computeDeviceClipBounds(bool outsetForAA) const {
1594 const SkBaseDevice* dev = this->topDevice();
1595 if (dev->onGetClipType() == SkBaseDevice::ClipType::kEmpty) {
1596 return SkRect::MakeEmpty();
1597 } else {
1598 SkRect devClipBounds = SkRect::Make(dev->devClipBounds());
1599 dev->deviceToGlobal().mapRect(&devClipBounds);
1600 if (outsetForAA) {
1601 // Expand bounds out by 1 in case we are anti-aliasing. We store the
1602 // bounds as floats to enable a faster quick reject implementation.
1603 devClipBounds.outset(1.f, 1.f);
1604 }
1605 return devClipBounds;
1606 }
1607 }
1608
1609 ///////////////////////////////////////////////////////////////////////
1610
getTotalMatrix() const1611 SkMatrix SkCanvas::getTotalMatrix() const {
1612 return fMCRec->fMatrix.asM33();
1613 }
1614
getLocalToDevice() const1615 SkM44 SkCanvas::getLocalToDevice() const {
1616 return fMCRec->fMatrix;
1617 }
1618
1619 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && SK_SUPPORT_GPU
1620
1621 #include "src/gpu/GrRenderTarget.h"
1622 #include "src/gpu/GrRenderTargetProxy.h"
1623 #include "src/gpu/GrSurfaceDrawContext.h"
1624
topLayerBounds() const1625 SkIRect SkCanvas::topLayerBounds() const {
1626 return this->topDevice()->getGlobalBounds();
1627 }
1628
topLayerBackendRenderTarget() const1629 GrBackendRenderTarget SkCanvas::topLayerBackendRenderTarget() const {
1630 const GrSurfaceDrawContext* sdc = const_cast<SkCanvas*>(this)->topDeviceSurfaceDrawContext();
1631 if (!sdc) {
1632 return {};
1633 }
1634 const GrRenderTargetProxy* proxy = sdc->asRenderTargetProxy();
1635 SkASSERT(proxy);
1636 const GrRenderTarget* renderTarget = proxy->peekRenderTarget();
1637 return renderTarget ? renderTarget->getBackendRenderTarget() : GrBackendRenderTarget();
1638 }
1639 #endif
1640
recordingContext()1641 GrRecordingContext* SkCanvas::recordingContext() {
1642 return this->topDevice()->recordingContext();
1643 }
1644
drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)1645 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1646 const SkPaint& paint) {
1647 TRACE_EVENT0("skia", TRACE_FUNC);
1648 if (outer.isEmpty()) {
1649 return;
1650 }
1651 if (inner.isEmpty()) {
1652 this->drawRRect(outer, paint);
1653 return;
1654 }
1655
1656 // We don't have this method (yet), but technically this is what we should
1657 // be able to return ...
1658 // if (!outer.contains(inner))) {
1659 //
1660 // For now at least check for containment of bounds
1661 if (!outer.getBounds().contains(inner.getBounds())) {
1662 return;
1663 }
1664
1665 this->onDrawDRRect(outer, inner, paint);
1666 }
1667
drawPaint(const SkPaint & paint)1668 void SkCanvas::drawPaint(const SkPaint& paint) {
1669 TRACE_EVENT0("skia", TRACE_FUNC);
1670 this->onDrawPaint(paint);
1671 }
1672
drawRect(const SkRect & r,const SkPaint & paint)1673 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1674 TRACE_EVENT0("skia", TRACE_FUNC);
1675 // To avoid redundant logic in our culling code and various backends, we always sort rects
1676 // before passing them along.
1677 this->onDrawRect(r.makeSorted(), paint);
1678 }
1679
drawClippedToSaveBehind(const SkPaint & paint)1680 void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1681 TRACE_EVENT0("skia", TRACE_FUNC);
1682 this->onDrawBehind(paint);
1683 }
1684
drawRegion(const SkRegion & region,const SkPaint & paint)1685 void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1686 TRACE_EVENT0("skia", TRACE_FUNC);
1687 if (region.isEmpty()) {
1688 return;
1689 }
1690
1691 if (region.isRect()) {
1692 return this->drawIRect(region.getBounds(), paint);
1693 }
1694
1695 this->onDrawRegion(region, paint);
1696 }
1697
drawOval(const SkRect & r,const SkPaint & paint)1698 void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1699 TRACE_EVENT0("skia", TRACE_FUNC);
1700 // To avoid redundant logic in our culling code and various backends, we always sort rects
1701 // before passing them along.
1702 this->onDrawOval(r.makeSorted(), paint);
1703 }
1704
drawRRect(const SkRRect & rrect,const SkPaint & paint)1705 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1706 TRACE_EVENT0("skia", TRACE_FUNC);
1707 this->onDrawRRect(rrect, paint);
1708 }
1709
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1710 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1711 TRACE_EVENT0("skia", TRACE_FUNC);
1712 this->onDrawPoints(mode, count, pts, paint);
1713 }
1714
drawVertices(const sk_sp<SkVertices> & vertices,SkBlendMode mode,const SkPaint & paint)1715 void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1716 const SkPaint& paint) {
1717 this->drawVertices(vertices.get(), mode, paint);
1718 }
1719
drawVertices(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)1720 void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1721 TRACE_EVENT0("skia", TRACE_FUNC);
1722 RETURN_ON_NULL(vertices);
1723
1724 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1725 SkASSERT(vertices->priv().mode() != SkVertices::kTriangleFan_VertexMode);
1726
1727 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1728 // Preserve legacy behavior for Android: ignore the SkShader if there are no texCoords present
1729 if (paint.getShader() && !vertices->priv().hasTexCoords()) {
1730 SkPaint noShaderPaint(paint);
1731 noShaderPaint.setShader(nullptr);
1732 this->onDrawVerticesObject(vertices, mode, noShaderPaint);
1733 return;
1734 }
1735 #endif
1736
1737 this->onDrawVerticesObject(vertices, mode, paint);
1738 }
1739
drawPath(const SkPath & path,const SkPaint & paint)1740 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1741 TRACE_EVENT0("skia", TRACE_FUNC);
1742 this->onDrawPath(path, paint);
1743 }
1744
1745 // Returns true if the rect can be "filled" : non-empty and finite
fillable(const SkRect & r)1746 static bool fillable(const SkRect& r) {
1747 SkScalar w = r.width();
1748 SkScalar h = r.height();
1749 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1750 }
1751
clean_paint_for_lattice(const SkPaint * paint)1752 static SkPaint clean_paint_for_lattice(const SkPaint* paint) {
1753 SkPaint cleaned;
1754 if (paint) {
1755 cleaned = *paint;
1756 cleaned.setMaskFilter(nullptr);
1757 cleaned.setAntiAlias(false);
1758 }
1759 return cleaned;
1760 }
1761
drawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)1762 void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1763 SkFilterMode filter, const SkPaint* paint) {
1764 RETURN_ON_NULL(image);
1765
1766 const int xdivs[] = {center.fLeft, center.fRight};
1767 const int ydivs[] = {center.fTop, center.fBottom};
1768
1769 Lattice lat;
1770 lat.fXDivs = xdivs;
1771 lat.fYDivs = ydivs;
1772 lat.fRectTypes = nullptr;
1773 lat.fXCount = lat.fYCount = 2;
1774 lat.fBounds = nullptr;
1775 lat.fColors = nullptr;
1776 this->drawImageLattice(image, lat, dst, filter, paint);
1777 }
1778
drawImageLattice(const SkImage * image,const Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)1779 void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1780 SkFilterMode filter, const SkPaint* paint) {
1781 TRACE_EVENT0("skia", TRACE_FUNC);
1782 RETURN_ON_NULL(image);
1783 if (dst.isEmpty()) {
1784 return;
1785 }
1786
1787 SkIRect bounds;
1788 Lattice latticePlusBounds = lattice;
1789 if (!latticePlusBounds.fBounds) {
1790 bounds = SkIRect::MakeWH(image->width(), image->height());
1791 latticePlusBounds.fBounds = &bounds;
1792 }
1793
1794 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1795 SkPaint latticePaint = clean_paint_for_lattice(paint);
1796 this->onDrawImageLattice2(image, latticePlusBounds, dst, filter, &latticePaint);
1797 } else {
1798 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst,
1799 SkSamplingOptions(filter), paint, kStrict_SrcRectConstraint);
1800 }
1801 }
1802
drawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode mode,const SkSamplingOptions & sampling,const SkRect * cull,const SkPaint * paint)1803 void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1804 const SkColor colors[], int count, SkBlendMode mode,
1805 const SkSamplingOptions& sampling, const SkRect* cull,
1806 const SkPaint* paint) {
1807 TRACE_EVENT0("skia", TRACE_FUNC);
1808 RETURN_ON_NULL(atlas);
1809 if (count <= 0) {
1810 return;
1811 }
1812 SkASSERT(atlas);
1813 SkASSERT(tex);
1814 this->onDrawAtlas2(atlas, xform, tex, colors, count, mode, sampling, cull, paint);
1815 }
1816
drawAnnotation(const SkRect & rect,const char key[],SkData * value)1817 void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1818 TRACE_EVENT0("skia", TRACE_FUNC);
1819 if (key) {
1820 this->onDrawAnnotation(rect, key, value);
1821 }
1822 }
1823
private_draw_shadow_rec(const SkPath & path,const SkDrawShadowRec & rec)1824 void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
1825 TRACE_EVENT0("skia", TRACE_FUNC);
1826 this->onDrawShadowRec(path, rec);
1827 }
1828
onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)1829 void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1830 // We don't test quickReject because the shadow outsets the path's bounds.
1831 // TODO(michaelludwig): Is it worth calling SkDrawShadowMetrics::GetLocalBounds here?
1832 this->predrawNotify();
1833 this->topDevice()->drawShadow(path, rec);
1834 }
1835
experimental_DrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)1836 void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
1837 QuadAAFlags aaFlags, const SkColor4f& color,
1838 SkBlendMode mode) {
1839 TRACE_EVENT0("skia", TRACE_FUNC);
1840 // Make sure the rect is sorted before passing it along
1841 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
1842 }
1843
experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[],int cnt,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)1844 void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
1845 const SkPoint dstClips[],
1846 const SkMatrix preViewMatrices[],
1847 const SkSamplingOptions& sampling,
1848 const SkPaint* paint,
1849 SrcRectConstraint constraint) {
1850 TRACE_EVENT0("skia", TRACE_FUNC);
1851 this->onDrawEdgeAAImageSet2(imageSet, cnt, dstClips, preViewMatrices, sampling, paint,
1852 constraint);
1853 }
1854
1855 //////////////////////////////////////////////////////////////////////////////
1856 // These are the virtual drawing methods
1857 //////////////////////////////////////////////////////////////////////////////
1858
onDiscard()1859 void SkCanvas::onDiscard() {
1860 if (fSurfaceBase) {
1861 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1862 }
1863 }
1864
onDrawPaint(const SkPaint & paint)1865 void SkCanvas::onDrawPaint(const SkPaint& paint) {
1866 this->internalDrawPaint(paint);
1867 }
1868
internalDrawPaint(const SkPaint & paint)1869 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1870 // drawPaint does not call internalQuickReject() because computing its geometry is not free
1871 // (see getLocalClipBounds(), and the two conditions below are sufficient.
1872 if (paint.nothingToDraw() || this->isClipEmpty()) {
1873 return;
1874 }
1875
1876 AutoLayerForImageFilter layer(this, paint, nullptr, CheckForOverwrite::kYes);
1877 this->topDevice()->drawPaint(layer.paint());
1878 }
1879
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1880 void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1881 const SkPaint& paint) {
1882 if ((long)count <= 0 || paint.nothingToDraw()) {
1883 return;
1884 }
1885 SkASSERT(pts != nullptr);
1886
1887 SkRect bounds;
1888 // Compute bounds from points (common for drawing a single line)
1889 if (count == 2) {
1890 bounds.set(pts[0], pts[1]);
1891 } else {
1892 bounds.setBounds(pts, SkToInt(count));
1893 }
1894
1895 // Enforce paint style matches implicit behavior of drawPoints
1896 SkPaint strokePaint = paint;
1897 strokePaint.setStyle(SkPaint::kStroke_Style);
1898 if (this->internalQuickReject(bounds, strokePaint)) {
1899 return;
1900 }
1901
1902 AutoLayerForImageFilter layer(this, strokePaint, &bounds);
1903 this->topDevice()->drawPoints(mode, count, pts, layer.paint());
1904 }
1905
onDrawRect(const SkRect & r,const SkPaint & paint)1906 void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
1907 SkASSERT(r.isSorted());
1908 if (this->internalQuickReject(r, paint)) {
1909 return;
1910 }
1911
1912 AutoLayerForImageFilter layer(this, paint, &r, CheckForOverwrite::kYes);
1913 this->topDevice()->drawRect(r, layer.paint());
1914 }
1915
onDrawRegion(const SkRegion & region,const SkPaint & paint)1916 void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
1917 const SkRect bounds = SkRect::Make(region.getBounds());
1918 if (this->internalQuickReject(bounds, paint)) {
1919 return;
1920 }
1921
1922 AutoLayerForImageFilter layer(this, paint, &bounds);
1923 this->topDevice()->drawRegion(region, layer.paint());
1924 }
1925
onDrawBehind(const SkPaint & paint)1926 void SkCanvas::onDrawBehind(const SkPaint& paint) {
1927 SkBaseDevice* dev = this->topDevice();
1928 if (!dev) {
1929 return;
1930 }
1931
1932 SkIRect bounds;
1933 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
1934 for (;;) {
1935 const MCRec* rec = (const MCRec*)iter.prev();
1936 if (!rec) {
1937 return; // no backimages, so nothing to draw
1938 }
1939 if (rec->fBackImage) {
1940 // drawBehind should only have been called when the saveBehind record is active;
1941 // if this fails, it means a real saveLayer was made w/o being restored first.
1942 SkASSERT(dev == rec->fDevice);
1943 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
1944 rec->fBackImage->fImage->width(),
1945 rec->fBackImage->fImage->height());
1946 break;
1947 }
1948 }
1949
1950 // The backimage location (and thus bounds) were defined in the device's space, so mark it
1951 // as a clip. We use a clip instead of just drawing a rect in case the paint has an image
1952 // filter on it (which is applied before any auto-layer so the filter is clipped).
1953 dev->save();
1954 {
1955 // We also have to temporarily whack the device matrix since clipRegion is affected by the
1956 // global-to-device matrix and clipRect is affected by the local-to-device.
1957 SkAutoDeviceTransformRestore adtr(dev, SkMatrix::I());
1958 dev->clipRect(SkRect::Make(bounds), SkClipOp::kIntersect, /* aa */ false);
1959 // ~adtr will reset the local-to-device matrix so that drawPaint() shades correctly.
1960 }
1961
1962 AutoLayerForImageFilter layer(this, paint);
1963 this->topDevice()->drawPaint(layer.paint());
1964
1965 dev->restore(fMCRec->fMatrix);
1966 }
1967
onDrawOval(const SkRect & oval,const SkPaint & paint)1968 void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
1969 SkASSERT(oval.isSorted());
1970 if (this->internalQuickReject(oval, paint)) {
1971 return;
1972 }
1973
1974 AutoLayerForImageFilter layer(this, paint, &oval);
1975 this->topDevice()->drawOval(oval, layer.paint());
1976 }
1977
onDrawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)1978 void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
1979 SkScalar sweepAngle, bool useCenter,
1980 const SkPaint& paint) {
1981 SkASSERT(oval.isSorted());
1982 if (this->internalQuickReject(oval, paint)) {
1983 return;
1984 }
1985
1986 AutoLayerForImageFilter layer(this, paint, &oval);
1987 this->topDevice()->drawArc(oval, startAngle, sweepAngle, useCenter, layer.paint());
1988 }
1989
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)1990 void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
1991 const SkRect& bounds = rrect.getBounds();
1992
1993 // Delegating to simpler draw operations
1994 if (rrect.isRect()) {
1995 // call the non-virtual version
1996 this->SkCanvas::drawRect(bounds, paint);
1997 return;
1998 } else if (rrect.isOval()) {
1999 // call the non-virtual version
2000 this->SkCanvas::drawOval(bounds, paint);
2001 return;
2002 }
2003
2004 if (this->internalQuickReject(bounds, paint)) {
2005 return;
2006 }
2007
2008 AutoLayerForImageFilter layer(this, paint, &bounds);
2009 this->topDevice()->drawRRect(rrect, layer.paint());
2010 }
2011
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)2012 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
2013 const SkRect& bounds = outer.getBounds();
2014 if (this->internalQuickReject(bounds, paint)) {
2015 return;
2016 }
2017
2018 AutoLayerForImageFilter layer(this, paint, &bounds);
2019 this->topDevice()->drawDRRect(outer, inner, layer.paint());
2020 }
2021
onDrawPath(const SkPath & path,const SkPaint & paint)2022 void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
2023 if (!path.isFinite()) {
2024 return;
2025 }
2026
2027 const SkRect& pathBounds = path.getBounds();
2028 if (!path.isInverseFillType() && this->internalQuickReject(pathBounds, paint)) {
2029 return;
2030 }
2031 if (path.isInverseFillType() && pathBounds.width() <= 0 && pathBounds.height() <= 0) {
2032 this->internalDrawPaint(paint);
2033 return;
2034 }
2035
2036 AutoLayerForImageFilter layer(this, paint, &pathBounds);
2037 this->topDevice()->drawPath(path, layer.paint());
2038 }
2039
canDrawBitmapAsSprite(SkScalar x,SkScalar y,int w,int h,const SkSamplingOptions & sampling,const SkPaint & paint)2040 bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h,
2041 const SkSamplingOptions& sampling, const SkPaint& paint) {
2042 if (!paint.getImageFilter()) {
2043 return false;
2044 }
2045
2046 const SkMatrix& ctm = this->getTotalMatrix();
2047 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), sampling, paint)) {
2048 return false;
2049 }
2050
2051 // The other paint effects need to be applied before the image filter, but the sprite draw
2052 // applies the filter explicitly first.
2053 if (paint.getAlphaf() < 1.f || paint.getColorFilter() || paint.getMaskFilter()) {
2054 return false;
2055 }
2056 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2057 // Once we can filter and the filter will return a result larger than itself, we should be
2058 // able to remove this constraint.
2059 // skbug.com/4526
2060 //
2061 SkPoint pt;
2062 ctm.mapXY(x, y, &pt);
2063 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2064 // quick bounds have been outset by 1px compared to overall device bounds, so this makes the
2065 // contains check equivalent to between ir and device bounds
2066 ir.outset(1, 1);
2067 return ir.contains(fQuickRejectBounds);
2068 }
2069
2070 // Clean-up the paint to match the drawing semantics for drawImage et al. (skbug.com/7804).
clean_paint_for_drawImage(const SkPaint * paint)2071 static SkPaint clean_paint_for_drawImage(const SkPaint* paint) {
2072 SkPaint cleaned;
2073 if (paint) {
2074 cleaned = *paint;
2075 cleaned.setStyle(SkPaint::kFill_Style);
2076 cleaned.setPathEffect(nullptr);
2077 }
2078 return cleaned;
2079 }
2080
2081 // drawVertices fills triangles and ignores mask filter and path effect,
2082 // so canonicalize the paint before checking quick reject.
clean_paint_for_drawVertices(SkPaint paint)2083 static SkPaint clean_paint_for_drawVertices(SkPaint paint) {
2084 paint.setStyle(SkPaint::kFill_Style);
2085 paint.setMaskFilter(nullptr);
2086 paint.setPathEffect(nullptr);
2087 return paint;
2088 }
2089
onDrawImage2(const SkImage * image,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)2090 void SkCanvas::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y,
2091 const SkSamplingOptions& sampling, const SkPaint* paint) {
2092 SkPaint realPaint = clean_paint_for_drawImage(paint);
2093
2094 SkRect bounds = SkRect::MakeXYWH(x, y, image->width(), image->height());
2095 if (this->internalQuickReject(bounds, realPaint)) {
2096 return;
2097 }
2098
2099 if (realPaint.getImageFilter() &&
2100 this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), sampling, realPaint) &&
2101 !image_to_color_filter(&realPaint)) {
2102 // Evaluate the image filter directly on the input image and then draw the result, instead
2103 // of first drawing the image to a temporary layer and filtering.
2104 SkBaseDevice* device = this->topDevice();
2105 sk_sp<SkSpecialImage> special;
2106 if ((special = device->makeSpecial(image))) {
2107 sk_sp<SkImageFilter> filter = realPaint.refImageFilter();
2108 realPaint.setImageFilter(nullptr);
2109
2110 // TODO(michaelludwig) - Many filters could probably be evaluated like this even if the
2111 // CTM is not translate-only; the post-transformation of the filtered image by the CTM
2112 // will probably look just as good and not require an extra layer.
2113 // TODO(michaelludwig) - Once image filter implementations can support source images
2114 // with non-(0,0) origins, we can just mark the origin as (x,y) instead of doing a
2115 // pre-concat here.
2116 SkMatrix layerToDevice = device->localToDevice();
2117 layerToDevice.preTranslate(x, y);
2118 skif::Mapping mapping(layerToDevice, SkMatrix::Translate(-x, -y));
2119
2120 this->predrawNotify();
2121 device->drawFilteredImage(mapping, special.get(), filter.get(), sampling, realPaint);
2122 return;
2123 } // else fall through to regular drawing path
2124 }
2125
2126 AutoLayerForImageFilter layer(this, realPaint, &bounds);
2127 this->topDevice()->drawImageRect(image, nullptr, bounds, sampling,
2128 layer.paint(), kStrict_SrcRectConstraint);
2129 }
2130
onDrawImageRect2(const SkImage * image,const SkRect & src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)2131 void SkCanvas::onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst,
2132 const SkSamplingOptions& sampling, const SkPaint* paint,
2133 SrcRectConstraint constraint) {
2134 SkPaint realPaint = clean_paint_for_drawImage(paint);
2135
2136 if (this->internalQuickReject(dst, realPaint)) {
2137 return;
2138 }
2139
2140 AutoLayerForImageFilter layer(this, realPaint, &dst, CheckForOverwrite::kYes,
2141 image->isOpaque() ? kOpaque_ShaderOverrideOpacity
2142 : kNotOpaque_ShaderOverrideOpacity);
2143 this->topDevice()->drawImageRect(image, &src, dst, sampling, layer.paint(), constraint);
2144 }
2145
onDrawImageLattice2(const SkImage * image,const Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)2146 void SkCanvas::onDrawImageLattice2(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2147 SkFilterMode filter, const SkPaint* paint) {
2148 SkPaint realPaint = clean_paint_for_drawImage(paint);
2149
2150 if (this->internalQuickReject(dst, realPaint)) {
2151 return;
2152 }
2153
2154 AutoLayerForImageFilter layer(this, realPaint, &dst);
2155 this->topDevice()->drawImageLattice(image, lattice, dst, filter, layer.paint());
2156 }
2157
drawImage(const SkImage * image,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)2158 void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y,
2159 const SkSamplingOptions& sampling, const SkPaint* paint) {
2160 TRACE_EVENT0("skia", TRACE_FUNC);
2161 RETURN_ON_NULL(image);
2162 this->onDrawImage2(image, x, y, sampling, paint);
2163 }
2164
drawImageRect(const SkImage * image,const SkRect & src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)2165 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
2166 const SkSamplingOptions& sampling, const SkPaint* paint,
2167 SrcRectConstraint constraint) {
2168 RETURN_ON_NULL(image);
2169 if (!fillable(dst) || !fillable(src)) {
2170 return;
2171 }
2172 this->onDrawImageRect2(image, src, dst, sampling, paint, constraint);
2173 }
2174
drawImageRect(const SkImage * image,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint)2175 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst,
2176 const SkSamplingOptions& sampling, const SkPaint* paint) {
2177 RETURN_ON_NULL(image);
2178 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, sampling,
2179 paint, kFast_SrcRectConstraint);
2180 }
2181
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2182 void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2183 const SkPaint& paint) {
2184 auto glyphRunList = fScratchGlyphRunBuilder->blobToGlyphRunList(*blob, {x, y});
2185 this->onDrawGlyphRunList(glyphRunList, paint);
2186 }
2187
onDrawGlyphRunList(const SkGlyphRunList & glyphRunList,const SkPaint & paint)2188 void SkCanvas::onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) {
2189 SkRect bounds = glyphRunList.sourceBounds();
2190 if (this->internalQuickReject(bounds, paint)) {
2191 return;
2192 }
2193 AutoLayerForImageFilter layer(this, paint, &bounds);
2194 this->topDevice()->drawGlyphRunList(glyphRunList, layer.paint());
2195 }
2196
2197 // 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)2198 void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
2199 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2200 TRACE_EVENT0("skia", TRACE_FUNC);
2201 if (byteLength) {
2202 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
2203 const SkGlyphRunList& glyphRunList =
2204 fScratchGlyphRunBuilder->textToGlyphRunList(
2205 font, paint, text, byteLength, {x, y}, encoding);
2206 if (!glyphRunList.empty()) {
2207 this->onDrawGlyphRunList(glyphRunList, paint);
2208 }
2209 }
2210 }
2211
drawGlyphs(int count,const SkGlyphID * glyphs,const SkPoint * positions,const uint32_t * clusters,int textByteCount,const char * utf8text,SkPoint origin,const SkFont & font,const SkPaint & paint)2212 void SkCanvas::drawGlyphs(int count, const SkGlyphID* glyphs, const SkPoint* positions,
2213 const uint32_t* clusters, int textByteCount, const char* utf8text,
2214 SkPoint origin, const SkFont& font, const SkPaint& paint) {
2215 if (count <= 0) { return; }
2216
2217 SkGlyphRun glyphRun {
2218 font,
2219 SkMakeSpan(positions, count),
2220 SkMakeSpan(glyphs, count),
2221 SkMakeSpan(utf8text, textByteCount),
2222 SkMakeSpan(clusters, count),
2223 SkSpan<SkVector>()
2224 };
2225 SkGlyphRunList glyphRunList {
2226 glyphRun,
2227 glyphRun.sourceBounds(paint).makeOffset(origin),
2228 origin
2229 };
2230 this->onDrawGlyphRunList(glyphRunList, paint);
2231 }
2232
drawGlyphs(int count,const SkGlyphID glyphs[],const SkPoint positions[],SkPoint origin,const SkFont & font,const SkPaint & paint)2233 void SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[],
2234 SkPoint origin, const SkFont& font, const SkPaint& paint) {
2235 if (count <= 0) { return; }
2236
2237 SkGlyphRun glyphRun {
2238 font,
2239 SkMakeSpan(positions, count),
2240 SkMakeSpan(glyphs, count),
2241 SkSpan<const char>(),
2242 SkSpan<const uint32_t>(),
2243 SkSpan<SkVector>()
2244 };
2245 SkGlyphRunList glyphRunList {
2246 glyphRun,
2247 glyphRun.sourceBounds(paint).makeOffset(origin),
2248 origin
2249 };
2250 this->onDrawGlyphRunList(glyphRunList, paint);
2251 }
2252
drawGlyphs(int count,const SkGlyphID glyphs[],const SkRSXform xforms[],SkPoint origin,const SkFont & font,const SkPaint & paint)2253 void SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkRSXform xforms[],
2254 SkPoint origin, const SkFont& font, const SkPaint& paint) {
2255 if (count <= 0) { return; }
2256
2257 auto [positions, rotateScales] =
2258 fScratchGlyphRunBuilder->convertRSXForm(SkMakeSpan(xforms, count));
2259
2260 SkGlyphRun glyphRun {
2261 font,
2262 positions,
2263 SkMakeSpan(glyphs, count),
2264 SkSpan<const char>(),
2265 SkSpan<const uint32_t>(),
2266 rotateScales
2267 };
2268 SkGlyphRunList glyphRunList {
2269 glyphRun,
2270 glyphRun.sourceBounds(paint).makeOffset(origin),
2271 origin
2272 };
2273 this->onDrawGlyphRunList(glyphRunList, paint);
2274 }
2275
drawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2276 void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2277 const SkPaint& paint) {
2278 TRACE_EVENT0("skia", TRACE_FUNC);
2279 RETURN_ON_NULL(blob);
2280 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
2281
2282 // Overflow if more than 2^21 glyphs stopping a buffer overflow latter in the stack.
2283 // See chromium:1080481
2284 // TODO: can consider unrolling a few at a time if this limit becomes a problem.
2285 int totalGlyphCount = 0;
2286 constexpr int kMaxGlyphCount = 1 << 21;
2287 SkTextBlob::Iter i(*blob);
2288 SkTextBlob::Iter::Run r;
2289 while (i.next(&r)) {
2290 int glyphsLeft = kMaxGlyphCount - totalGlyphCount;
2291 RETURN_ON_FALSE(r.fGlyphCount <= glyphsLeft);
2292 totalGlyphCount += r.fGlyphCount;
2293 }
2294 this->onDrawTextBlob(blob, x, y, paint);
2295 }
2296
onDrawVerticesObject(const SkVertices * vertices,SkBlendMode bmode,const SkPaint & paint)2297 void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2298 const SkPaint& paint) {
2299 SkPaint simplePaint = clean_paint_for_drawVertices(paint);
2300
2301 const SkRect& bounds = vertices->bounds();
2302 if (this->internalQuickReject(bounds, simplePaint)) {
2303 return;
2304 }
2305
2306 AutoLayerForImageFilter layer(this, simplePaint, &bounds);
2307 this->topDevice()->drawVertices(vertices, bmode, layer.paint());
2308 }
2309
drawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)2310 void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2311 const SkPoint texCoords[4], SkBlendMode bmode,
2312 const SkPaint& paint) {
2313 TRACE_EVENT0("skia", TRACE_FUNC);
2314 if (nullptr == cubics) {
2315 return;
2316 }
2317
2318 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
2319 }
2320
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)2321 void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2322 const SkPoint texCoords[4], SkBlendMode bmode,
2323 const SkPaint& paint) {
2324 // drawPatch has the same behavior restrictions as drawVertices
2325 SkPaint simplePaint = clean_paint_for_drawVertices(paint);
2326
2327 // Since a patch is always within the convex hull of the control points, we discard it when its
2328 // bounding rectangle is completely outside the current clip.
2329 SkRect bounds;
2330 bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts);
2331 if (this->internalQuickReject(bounds, simplePaint)) {
2332 return;
2333 }
2334
2335 AutoLayerForImageFilter layer(this, simplePaint, &bounds);
2336 this->topDevice()->drawPatch(cubics, colors, texCoords, bmode, layer.paint());
2337 }
2338
drawDrawable(SkDrawable * dr,SkScalar x,SkScalar y)2339 void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2340 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2341 TRACE_EVENT0("skia", TRACE_FUNC);
2342 #endif
2343 RETURN_ON_NULL(dr);
2344 if (x || y) {
2345 SkMatrix matrix = SkMatrix::Translate(x, y);
2346 this->onDrawDrawable(dr, &matrix);
2347 } else {
2348 this->onDrawDrawable(dr, nullptr);
2349 }
2350 }
2351
drawDrawable(SkDrawable * dr,const SkMatrix * matrix)2352 void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2353 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2354 TRACE_EVENT0("skia", TRACE_FUNC);
2355 #endif
2356 RETURN_ON_NULL(dr);
2357 if (matrix && matrix->isIdentity()) {
2358 matrix = nullptr;
2359 }
2360 this->onDrawDrawable(dr, matrix);
2361 }
2362
onDrawDrawable(SkDrawable * dr,const SkMatrix * matrix)2363 void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2364 // drawable bounds are no longer reliable (e.g. android displaylist)
2365 // so don't use them for quick-reject
2366 this->predrawNotify();
2367 this->baseDevice()->drawDrawable(dr, matrix, this);
2368 }
2369
onDrawAtlas2(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode bmode,const SkSamplingOptions & sampling,const SkRect * cull,const SkPaint * paint)2370 void SkCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2371 const SkColor colors[], int count, SkBlendMode bmode,
2372 const SkSamplingOptions& sampling, const SkRect* cull,
2373 const SkPaint* paint) {
2374 // drawAtlas is a combination of drawVertices and drawImage...
2375 SkPaint realPaint = clean_paint_for_drawVertices(clean_paint_for_drawImage(paint));
2376
2377 if (cull && this->internalQuickReject(*cull, realPaint)) {
2378 return;
2379 }
2380
2381 AutoLayerForImageFilter layer(this, realPaint);
2382 this->topDevice()->drawAtlas(atlas, xform, tex, colors, count, bmode, sampling, layer.paint());
2383 }
2384
onDrawAnnotation(const SkRect & rect,const char key[],SkData * value)2385 void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2386 SkASSERT(key);
2387
2388 this->predrawNotify();
2389 this->topDevice()->drawAnnotation(rect, key, value);
2390 }
2391
onDrawEdgeAAQuad(const SkRect & r,const SkPoint clip[4],QuadAAFlags edgeAA,const SkColor4f & color,SkBlendMode mode)2392 void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2393 const SkColor4f& color, SkBlendMode mode) {
2394 SkASSERT(r.isSorted());
2395
2396 SkPaint paint{color};
2397 paint.setBlendMode(mode);
2398 if (this->internalQuickReject(r, paint)) {
2399 return;
2400 }
2401
2402 this->predrawNotify();
2403 this->topDevice()->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2404 }
2405
onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)2406 void SkCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count,
2407 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2408 const SkSamplingOptions& sampling, const SkPaint* paint,
2409 SrcRectConstraint constraint) {
2410 if (count <= 0) {
2411 // Nothing to draw
2412 return;
2413 }
2414
2415 SkPaint realPaint = clean_paint_for_drawImage(paint);
2416
2417 // We could calculate the set's dstRect union to always check quickReject(), but we can't reject
2418 // individual entries and Chromium's occlusion culling already makes it likely that at least one
2419 // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1),
2420 // or we need it for the autolooper (since it greatly improves image filter perf).
2421 bool needsAutoLayer = SkToBool(realPaint.getImageFilter());
2422 bool setBoundsValid = count == 1 || needsAutoLayer;
2423 SkRect setBounds = imageSet[0].fDstRect;
2424 if (imageSet[0].fMatrixIndex >= 0) {
2425 // Account for the per-entry transform that is applied prior to the CTM when drawing
2426 preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds);
2427 }
2428 if (needsAutoLayer) {
2429 for (int i = 1; i < count; ++i) {
2430 SkRect entryBounds = imageSet[i].fDstRect;
2431 if (imageSet[i].fMatrixIndex >= 0) {
2432 preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds);
2433 }
2434 setBounds.joinPossiblyEmptyRect(entryBounds);
2435 }
2436 }
2437
2438 // If we happen to have the draw bounds, though, might as well check quickReject().
2439 if (setBoundsValid && this->internalQuickReject(setBounds, realPaint)) {
2440 return;
2441 }
2442
2443 AutoLayerForImageFilter layer(this, realPaint, setBoundsValid ? &setBounds : nullptr);
2444 this->topDevice()->drawEdgeAAImageSet(imageSet, count, dstClips, preViewMatrices, sampling,
2445 layer.paint(), constraint);
2446 }
2447
2448 //////////////////////////////////////////////////////////////////////////////
2449 // These methods are NOT virtual, and therefore must call back into virtual
2450 // methods, rather than actually drawing themselves.
2451 //////////////////////////////////////////////////////////////////////////////
2452
drawColor(const SkColor4f & c,SkBlendMode mode)2453 void SkCanvas::drawColor(const SkColor4f& c, SkBlendMode mode) {
2454 SkPaint paint;
2455 paint.setColor(c);
2456 paint.setBlendMode(mode);
2457 this->drawPaint(paint);
2458 }
2459
drawPoint(SkScalar x,SkScalar y,const SkPaint & paint)2460 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2461 const SkPoint pt = { x, y };
2462 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2463 }
2464
drawLine(SkScalar x0,SkScalar y0,SkScalar x1,SkScalar y1,const SkPaint & paint)2465 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
2466 SkPoint pts[2];
2467 pts[0].set(x0, y0);
2468 pts[1].set(x1, y1);
2469 this->drawPoints(kLines_PointMode, 2, pts, paint);
2470 }
2471
drawCircle(SkScalar cx,SkScalar cy,SkScalar radius,const SkPaint & paint)2472 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
2473 if (radius < 0) {
2474 radius = 0;
2475 }
2476
2477 SkRect r;
2478 r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
2479 this->drawOval(r, paint);
2480 }
2481
drawRoundRect(const SkRect & r,SkScalar rx,SkScalar ry,const SkPaint & paint)2482 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2483 const SkPaint& paint) {
2484 if (rx > 0 && ry > 0) {
2485 SkRRect rrect;
2486 rrect.setRectXY(r, rx, ry);
2487 this->drawRRect(rrect, paint);
2488 } else {
2489 this->drawRect(r, paint);
2490 }
2491 }
2492
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)2493 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2494 SkScalar sweepAngle, bool useCenter,
2495 const SkPaint& paint) {
2496 TRACE_EVENT0("skia", TRACE_FUNC);
2497 if (oval.isEmpty() || !sweepAngle) {
2498 return;
2499 }
2500 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
2501 }
2502
2503 ///////////////////////////////////////////////////////////////////////////////
2504 #ifdef SK_DISABLE_SKPICTURE
drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2505 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
2506
2507
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2508 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2509 const SkPaint* paint) {}
2510 #else
2511
drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2512 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2513 TRACE_EVENT0("skia", TRACE_FUNC);
2514 RETURN_ON_NULL(picture);
2515
2516 if (matrix && matrix->isIdentity()) {
2517 matrix = nullptr;
2518 }
2519 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2520 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2521 picture->playback(this);
2522 } else {
2523 this->onDrawPicture(picture, matrix, paint);
2524 }
2525 }
2526
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2527 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2528 const SkPaint* paint) {
2529 if (this->internalQuickReject(picture->cullRect(), paint ? *paint : SkPaint{}, matrix)) {
2530 return;
2531 }
2532
2533 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2534 picture->playback(this);
2535 }
2536 #endif
2537
2538 ///////////////////////////////////////////////////////////////////////////////
2539
2540 SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2541 SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2542 SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2543 SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2544
ImageSetEntry(sk_sp<const SkImage> image,const SkRect & srcRect,const SkRect & dstRect,int matrixIndex,float alpha,unsigned aaFlags,bool hasClip)2545 SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2546 const SkRect& dstRect, int matrixIndex, float alpha,
2547 unsigned aaFlags, bool hasClip)
2548 : fImage(std::move(image))
2549 , fSrcRect(srcRect)
2550 , fDstRect(dstRect)
2551 , fMatrixIndex(matrixIndex)
2552 , fAlpha(alpha)
2553 , fAAFlags(aaFlags)
2554 , fHasClip(hasClip) {}
2555
ImageSetEntry(sk_sp<const SkImage> image,const SkRect & srcRect,const SkRect & dstRect,float alpha,unsigned aaFlags)2556 SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2557 const SkRect& dstRect, float alpha, unsigned aaFlags)
2558 : fImage(std::move(image))
2559 , fSrcRect(srcRect)
2560 , fDstRect(dstRect)
2561 , fAlpha(alpha)
2562 , fAAFlags(aaFlags) {}
2563
2564 ///////////////////////////////////////////////////////////////////////////////
2565
MakeRasterDirect(const SkImageInfo & info,void * pixels,size_t rowBytes,const SkSurfaceProps * props)2566 std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
2567 size_t rowBytes, const SkSurfaceProps* props) {
2568 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
2569 return nullptr;
2570 }
2571
2572 SkBitmap bitmap;
2573 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2574 return nullptr;
2575 }
2576
2577 return props ?
2578 std::make_unique<SkCanvas>(bitmap, *props) :
2579 std::make_unique<SkCanvas>(bitmap);
2580 }
2581
2582 ///////////////////////////////////////////////////////////////////////////////
2583
SkNoDrawCanvas(int width,int height)2584 SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2585 : INHERITED(SkIRect::MakeWH(width, height)) {}
2586
SkNoDrawCanvas(const SkIRect & bounds)2587 SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2588 : INHERITED(bounds) {}
2589
SkNoDrawCanvas(sk_sp<SkBaseDevice> device)2590 SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
2591 : INHERITED(device) {}
2592
getSaveLayerStrategy(const SaveLayerRec & rec)2593 SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2594 (void)this->INHERITED::getSaveLayerStrategy(rec);
2595 return kNoLayer_SaveLayerStrategy;
2596 }
2597
onDoSaveBehind(const SkRect *)2598 bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2599 return false;
2600 }
2601
2602 ///////////////////////////////////////////////////////////////////////////////
2603
2604 static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2605 static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2606 static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2607 static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2608 static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2609 static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
2610
2611 ///////////////////////////////////////////////////////////////////////////////////////////////////
2612
accessTopRasterHandle() const2613 SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2614 const SkBaseDevice* dev = this->topDevice();
2615 if (fAllocator) {
2616 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2617 SkIRect clip = dev->devClipBounds();
2618 if (!clip.intersect({0, 0, dev->width(), dev->height()})) {
2619 clip.setEmpty();
2620 }
2621
2622 fAllocator->updateHandle(handle, dev->localToDevice(), clip);
2623 return handle;
2624 }
2625 return nullptr;
2626 }
2627
install(SkBitmap * bm,const SkImageInfo & info,const SkRasterHandleAllocator::Rec & rec)2628 static bool install(SkBitmap* bm, const SkImageInfo& info,
2629 const SkRasterHandleAllocator::Rec& rec) {
2630 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
2631 }
2632
allocBitmap(const SkImageInfo & info,SkBitmap * bm)2633 SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2634 SkBitmap* bm) {
2635 SkRasterHandleAllocator::Rec rec;
2636 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2637 return nullptr;
2638 }
2639 return rec.fHandle;
2640 }
2641
2642 std::unique_ptr<SkCanvas>
MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,const SkImageInfo & info,const Rec * rec)2643 SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2644 const SkImageInfo& info, const Rec* rec) {
2645 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
2646 return nullptr;
2647 }
2648
2649 SkBitmap bm;
2650 Handle hndl;
2651
2652 if (rec) {
2653 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2654 } else {
2655 hndl = alloc->allocBitmap(info, &bm);
2656 }
2657 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2658 }
2659
2660 ///////////////////////////////////////////////////////////////////////////////////////////////////
2661