blob: 1ab386786a19e5f602f4e8e486af2f152d61d66c [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkCanvas.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkColorFilter.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "include/private/SkNx.h"
21#include "include/private/SkTo.h"
22#include "include/utils/SkNoDrawCanvas.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040023#include "src/core/SkArenaAlloc.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#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"
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040031#include "src/core/SkImageFilter_Base.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050032#include "src/core/SkLatticeIter.h"
33#include "src/core/SkMSAN.h"
34#include "src/core/SkMakeUnique.h"
35#include "src/core/SkMatrixUtils.h"
36#include "src/core/SkPaintPriv.h"
37#include "src/core/SkRasterClip.h"
38#include "src/core/SkSpecialImage.h"
39#include "src/core/SkStrikeCache.h"
40#include "src/core/SkTLazy.h"
41#include "src/core/SkTextFormatParams.h"
42#include "src/core/SkTraceEvent.h"
43#include "src/image/SkImage_Base.h"
44#include "src/image/SkSurface_Base.h"
45#include "src/utils/SkPatchUtils.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040046
bungemand3ebb482015-08-05 13:57:49 -070047#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000048
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000049#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050050#include "include/gpu/GrContext.h"
51#include "src/gpu/SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052#endif
53
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050055#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080056
Mike Reed139e5e02017-03-08 11:29:33 -050057///////////////////////////////////////////////////////////////////////////////////////////////////
58
reedc83a2972015-07-16 07:40:45 -070059/*
60 * Return true if the drawing this rect would hit every pixels in the canvas.
61 *
62 * Returns false if
63 * - rect does not contain the canvas' bounds
64 * - paint is not fill
65 * - paint would blur or otherwise change the coverage of the rect
66 */
67bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
68 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070069 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
70 (int)kNone_ShaderOverrideOpacity,
71 "need_matching_enums0");
72 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
73 (int)kOpaque_ShaderOverrideOpacity,
74 "need_matching_enums1");
75 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
76 (int)kNotOpaque_ShaderOverrideOpacity,
77 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070078
79 const SkISize size = this->getBaseLayerSize();
80 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050081
82 // if we're clipped at all, we can't overwrite the entire surface
83 {
84 SkBaseDevice* base = this->getDevice();
85 SkBaseDevice* top = this->getTopDevice();
86 if (base != top) {
87 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
88 }
89 if (!base->clipIsWideOpen()) {
90 return false;
91 }
reedc83a2972015-07-16 07:40:45 -070092 }
93
94 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070095 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070096 return false; // conservative
97 }
halcanaryc5769b22016-08-10 07:13:21 -070098
99 SkRect devRect;
100 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
101 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700102 return false;
103 }
104 }
105
106 if (paint) {
107 SkPaint::Style paintStyle = paint->getStyle();
108 if (!(paintStyle == SkPaint::kFill_Style ||
109 paintStyle == SkPaint::kStrokeAndFill_Style)) {
110 return false;
111 }
Mike Reed9dc0b9e2019-07-29 17:52:48 -0400112 if (paint->getMaskFilter() || paint->getPathEffect() || paint->getImageFilter()) {
reedc83a2972015-07-16 07:40:45 -0700113 return false; // conservative
114 }
115 }
116 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
117}
118
119///////////////////////////////////////////////////////////////////////////////////////////////////
120
reed@google.comda17f752012-08-16 18:27:05 +0000121// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122//#define SK_TRACE_SAVERESTORE
123
124#ifdef SK_TRACE_SAVERESTORE
125 static int gLayerCounter;
126 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
127 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
128
129 static int gRecCounter;
130 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
131 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
132
133 static int gCanvasCounter;
134 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
135 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
136#else
137 #define inc_layer()
138 #define dec_layer()
139 #define inc_rec()
140 #define dec_rec()
141 #define inc_canvas()
142 #define dec_canvas()
143#endif
144
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000145typedef SkTLazy<SkPaint> SkLazyPaint;
146
reedc83a2972015-07-16 07:40:45 -0700147void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000148 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700149 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
150 ? SkSurface::kDiscard_ContentChangeMode
151 : SkSurface::kRetain_ContentChangeMode);
152 }
153}
154
155void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
156 ShaderOverrideOpacity overrideOpacity) {
157 if (fSurfaceBase) {
158 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
159 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
160 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
161 // and therefore we don't care which mode we're in.
162 //
163 if (fSurfaceBase->outstandingImageSnapshot()) {
164 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
165 mode = SkSurface::kDiscard_ContentChangeMode;
166 }
167 }
168 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000169 }
170}
171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000174/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 The clip/matrix/proc are fields that reflect the top of the save/restore
176 stack. Whenever the canvas changes, it marks a dirty flag, and then before
177 these are used (assuming we're not on a layer) we rebuild these cache
178 values: they reflect the top of the save stack, but translated and clipped
179 by the device's XY offset and bitmap-bounds.
180*/
181struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400182 DeviceCM* fNext;
183 sk_sp<SkBaseDevice> fDevice;
184 SkRasterClip fClip;
185 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
186 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400187 sk_sp<SkImage> fClipImage;
188 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189
Florin Malita53f77bd2017-04-28 13:48:37 -0400190 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000191 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700192 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400193 , fDevice(std::move(device))
194 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700195 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000196 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400197 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400198 {}
reed@google.com4b226022011-01-11 18:32:13 +0000199
mtkleinfeaadee2015-04-08 11:25:48 -0700200 void reset(const SkIRect& bounds) {
201 SkASSERT(!fPaint);
202 SkASSERT(!fNext);
203 SkASSERT(fDevice);
204 fClip.setRect(bounds);
205 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206};
207
Mike Reed148b7fd2018-12-18 17:38:18 -0500208namespace {
209// Encapsulate state needed to restore from saveBehind()
210struct BackImage {
211 sk_sp<SkSpecialImage> fImage;
212 SkIPoint fLoc;
213};
214}
215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216/* This is the record we keep for each save/restore level in the stack.
217 Since a level optionally copies the matrix and/or stack, we have pointers
218 for these fields. If the value is copied for this level, the copy is
219 stored in the ...Storage field, and the pointer points to that. If the
220 value is not copied for this level, we ignore ...Storage, and just point
221 at the corresponding value in the previous level in the stack.
222*/
223class SkCanvas::MCRec {
224public:
Mike Reed148b7fd2018-12-18 17:38:18 -0500225 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 /* If there are any layers in the stack, this points to the top-most
227 one that is at or below this level in the stack (so we know what
228 bitmap/device to draw into from this level. This value is NOT
229 reference counted, since the real owner is either our fLayer field,
230 or a previous one in a lower level.)
231 */
Mike Reed148b7fd2018-12-18 17:38:18 -0500232 DeviceCM* fTopLayer;
233 std::unique_ptr<BackImage> fBackImage;
234 SkConservativeClip fRasterClip;
235 SkMatrix fMatrix;
236 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
Mike Reeda1361362017-03-07 09:37:29 -0500238 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700239 fLayer = nullptr;
240 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800241 fMatrix.reset();
242 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700243
reedd9544982014-09-09 18:46:22 -0700244 // don't bother initializing fNext
245 inc_rec();
246 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400247 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700248 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700249 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800250 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700251
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 // don't bother initializing fNext
253 inc_rec();
254 }
255 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700256 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 dec_rec();
258 }
mtkleinfeaadee2015-04-08 11:25:48 -0700259
260 void reset(const SkIRect& bounds) {
261 SkASSERT(fLayer);
262 SkASSERT(fDeferredSaveCount == 0);
263
264 fMatrix.reset();
265 fRasterClip.setRect(bounds);
266 fLayer->reset(bounds);
267 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268};
269
Mike Reeda1361362017-03-07 09:37:29 -0500270class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271public:
Mike Reeda1361362017-03-07 09:37:29 -0500272 SkDrawIter(SkCanvas* canvas)
273 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
274 {}
reed@google.com4b226022011-01-11 18:32:13 +0000275
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000277 const DeviceCM* rec = fCurrLayer;
278 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400279 fDevice = rec->fDevice.get();
280 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700282 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 return true;
284 }
285 return false;
286 }
reed@google.com4b226022011-01-11 18:32:13 +0000287
reed@google.com6f8f2922011-03-04 22:27:10 +0000288 int getX() const { return fDevice->getOrigin().x(); }
289 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000291
Mike Reed99330ba2017-02-22 11:01:08 -0500292 SkBaseDevice* fDevice;
293
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 const DeviceCM* fCurrLayer;
296 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297};
298
Florin Malita713b8ef2017-04-28 10:57:24 -0400299#define FOR_EACH_TOP_DEVICE( code ) \
300 do { \
301 DeviceCM* layer = fMCRec->fTopLayer; \
302 while (layer) { \
303 SkBaseDevice* device = layer->fDevice.get(); \
304 if (device) { \
305 code; \
306 } \
307 layer = layer->fNext; \
308 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500309 } while (0)
310
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311/////////////////////////////////////////////////////////////////////////////
312
reeddbc3cef2015-04-29 12:18:57 -0700313/**
314 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700315 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700316 */
reedd053ce92016-03-22 10:17:23 -0700317static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700318 SkImageFilter* imgf = paint.getImageFilter();
319 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700320 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700321 }
322
reedd053ce92016-03-22 10:17:23 -0700323 SkColorFilter* imgCFPtr;
324 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700325 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700326 }
reedd053ce92016-03-22 10:17:23 -0700327 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700328
329 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700330 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700331 // there is no existing paint colorfilter, so we can just return the imagefilter's
332 return imgCF;
333 }
334
335 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
336 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500337 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700338}
339
senorblanco87e066e2015-10-28 11:23:36 -0700340/**
341 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
342 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
343 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
344 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
345 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
346 * conservative "effective" bounds based on the settings in the paint... with one exception. This
347 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
348 * deliberately ignored.
349 */
350static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
351 const SkRect& rawBounds,
352 SkRect* storage) {
353 SkPaint tmpUnfiltered(paint);
354 tmpUnfiltered.setImageFilter(nullptr);
355 if (tmpUnfiltered.canComputeFastBounds()) {
356 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
357 } else {
358 return rawBounds;
359 }
360}
361
Mike Reed38992392019-07-30 10:48:15 -0400362class AutoLayerForImageFilter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363public:
senorblanco87e066e2015-10-28 11:23:36 -0700364 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
365 // paint. It's used to determine the size of the offscreen layer for filters.
366 // If null, the clip will be used instead.
Mike Reed38992392019-07-30 10:48:15 -0400367 AutoLayerForImageFilter(SkCanvas* canvas, const SkPaint& origPaint,
368 bool skipLayerForImageFilter = false,
369 const SkRect* rawBounds = nullptr) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000370 fCanvas = canvas;
Mike Reed38992392019-07-30 10:48:15 -0400371 fPaint = &origPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000372 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700373 fTempLayerForImageFilter = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374
Mike Reed38992392019-07-30 10:48:15 -0400375 if (auto simplifiedCF = image_to_color_filter(origPaint)) {
376 SkASSERT(!fLazyPaint.isValid());
377 SkPaint* paint = fLazyPaint.set(origPaint);
reedd053ce92016-03-22 10:17:23 -0700378 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700379 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700380 fPaint = paint;
381 }
382
383 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700384 /**
385 * We implement ImageFilters for a given draw by creating a layer, then applying the
386 * imagefilter to the pixels of that layer (its backing surface/image), and then
387 * we call restore() to xfer that layer to the main canvas.
388 *
389 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
390 * 2. Generate the src pixels:
391 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
392 * return (fPaint). We then draw the primitive (using srcover) into a cleared
393 * buffer/surface.
394 * 3. Restore the layer created in #1
395 * The imagefilter is passed the buffer/surface from the layer (now filled with the
396 * src pixels of the primitive). It returns a new "filtered" buffer, which we
397 * draw onto the previous layer using the xfermode from the original paint.
398 */
Mike Reed38992392019-07-30 10:48:15 -0400399
400 SkPaint restorePaint;
401 restorePaint.setImageFilter(fPaint->refImageFilter());
402 restorePaint.setBlendMode(fPaint->getBlendMode());
403
senorblanco87e066e2015-10-28 11:23:36 -0700404 SkRect storage;
405 if (rawBounds) {
406 // Make rawBounds include all paint outsets except for those due to image filters.
407 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
408 }
Mike Reed38992392019-07-30 10:48:15 -0400409 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &restorePaint),
reed76033be2015-03-14 10:54:31 -0700410 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700411 fTempLayerForImageFilter = true;
reed@google.com8926b162012-03-23 15:36:36 +0000412
Mike Reed38992392019-07-30 10:48:15 -0400413 // Remove the restorePaint fields from our "working" paint
414 SkASSERT(!fLazyPaint.isValid());
415 SkPaint* paint = fLazyPaint.set(origPaint);
416 paint->setImageFilter(nullptr);
417 paint->setBlendMode(SkBlendMode::kSrcOver);
418 fPaint = paint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000419 }
420 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000421
Mike Reed38992392019-07-30 10:48:15 -0400422 ~AutoLayerForImageFilter() {
reed5c476fb2015-04-20 08:04:21 -0700423 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000424 fCanvas->internalRestore();
425 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000426 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000428
reed@google.com4e2b3d32011-04-07 14:18:59 +0000429 const SkPaint& paint() const {
430 SkASSERT(fPaint);
431 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000433
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434private:
Mike Reed38992392019-07-30 10:48:15 -0400435 SkLazyPaint fLazyPaint; // base paint storage in case we need to modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000436 SkCanvas* fCanvas;
Mike Reed38992392019-07-30 10:48:15 -0400437 const SkPaint* fPaint; // points to either the original paint, or lazy (if we needed it)
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000438 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700439 bool fTempLayerForImageFilter;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440};
441
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442////////// macros to place around the internal draw calls //////////////////
443
Mike Reed38992392019-07-30 10:48:15 -0400444#define DRAW_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
reed3aafe112016-08-18 12:45:34 -0700445 this->predrawNotify(); \
Mike Reed38992392019-07-30 10:48:15 -0400446 AutoLayerForImageFilter draw(this, paint, skipLayerForFilter, bounds); \
447 { SkDrawIter iter(this);
reed262a71b2015-12-05 13:07:27 -0800448
449
Mike Reed38992392019-07-30 10:48:15 -0400450#define DRAW_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000451 this->predrawNotify(); \
Mike Reed38992392019-07-30 10:48:15 -0400452 AutoLayerForImageFilter draw(this, paint, true); \
453 { SkDrawIter iter(this);
reed@google.com8926b162012-03-23 15:36:36 +0000454
Mike Reed38992392019-07-30 10:48:15 -0400455#define DRAW_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000456 this->predrawNotify(); \
Mike Reed38992392019-07-30 10:48:15 -0400457 AutoLayerForImageFilter draw(this, paint, false, bounds); \
458 { SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000459
Mike Reed38992392019-07-30 10:48:15 -0400460#define DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700461 this->predrawNotify(bounds, &paint, auxOpaque); \
Mike Reed38992392019-07-30 10:48:15 -0400462 AutoLayerForImageFilter draw(this, paint, false, bounds); \
463 { SkDrawIter iter(this);
reedc83a2972015-07-16 07:40:45 -0700464
Mike Reed38992392019-07-30 10:48:15 -0400465#define DRAW_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466
467////////////////////////////////////////////////////////////////////////////
468
msarettfbfa2582016-08-12 08:29:08 -0700469static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
470 if (bounds.isEmpty()) {
471 return SkRect::MakeEmpty();
472 }
473
474 // Expand bounds out by 1 in case we are anti-aliasing. We store the
475 // bounds as floats to enable a faster quick reject implementation.
476 SkRect dst;
477 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
478 return dst;
479}
480
mtkleinfeaadee2015-04-08 11:25:48 -0700481void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
482 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700483 fMCRec->reset(bounds);
484
485 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500486 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400487 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700488 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700489 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700490}
491
Hal Canary363a3f82018-10-04 11:04:48 -0400492void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000493 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800494 fSaveCount = 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495
496 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500497 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500498 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700499 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000500
reeda499f902015-05-01 09:34:31 -0700501 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
502 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400503 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700504
reed@android.com8a1c16f2008-12-17 15:59:43 +0000505 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506
halcanary96fcdcc2015-08-27 07:41:13 -0700507 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000508
reedf92c8662014-08-18 08:02:43 -0700509 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700510 // The root device and the canvas should always have the same pixel geometry
511 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800512 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700513 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500514
Mike Reedc42a1cd2017-02-14 14:25:14 -0500515 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700516 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400517
Herb Derby59d997a2018-06-07 12:44:09 -0400518 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519}
520
reed@google.comcde92112011-07-06 20:00:52 +0000521SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000522 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700523 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000524{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000525 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000526
Hal Canary363a3f82018-10-04 11:04:48 -0400527 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000528}
529
reed96a857e2015-01-25 10:33:58 -0800530SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000531 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800532 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000533{
534 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400535 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400536 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700537}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000538
Hal Canary363a3f82018-10-04 11:04:48 -0400539SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700540 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700541 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700542{
543 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700544
Mike Reed566e53c2017-03-10 10:49:45 -0500545 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400546 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700547}
548
Herb Derbyefe39bc2018-05-01 17:06:20 -0400549SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000550 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700551 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000552{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700554
Hal Canary363a3f82018-10-04 11:04:48 -0400555 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700556}
557
reed4a8126e2014-09-22 07:29:03 -0700558SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700559 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700560 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700561{
562 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700563
Mike Reed910ca0f2018-04-25 13:04:05 -0400564 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400565 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700566}
reed29c857d2014-09-21 10:25:07 -0700567
Mike Reed356f7c22017-01-10 11:58:39 -0500568SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
569 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700570 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
571 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500572 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700573{
574 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700575
Mike Reed910ca0f2018-04-25 13:04:05 -0400576 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400577 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578}
579
Mike Reed356f7c22017-01-10 11:58:39 -0500580SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
581
Matt Sarett31f99ce2017-04-11 08:46:01 -0400582#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
583SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
584 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
585 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
586 , fAllocator(nullptr)
587{
588 inc_canvas();
589
590 SkBitmap tmp(bitmap);
591 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400592 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400593 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400594}
595#endif
596
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597SkCanvas::~SkCanvas() {
598 // free up the contents of our deque
599 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000600
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601 this->internalRestore(); // restore the last, since we're going away
602
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603 dec_canvas();
604}
605
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606///////////////////////////////////////////////////////////////////////////////
607
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000608void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700609 this->onFlush();
610}
611
612void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000613 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000614 if (device) {
615 device->flush();
616 }
617}
618
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000619SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000620 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000621 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
622}
623
senorblancoafc7cce2016-02-02 18:44:15 -0800624SkIRect SkCanvas::getTopLayerBounds() const {
625 SkBaseDevice* d = this->getTopDevice();
626 if (!d) {
627 return SkIRect::MakeEmpty();
628 }
629 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
630}
631
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000632SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000634 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000635 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400636 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637}
638
Florin Malita0ed3b642017-01-13 16:56:38 +0000639SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400640 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000641}
642
Mike Reed353196f2017-07-21 11:01:18 -0400643bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000644 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400645 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000646}
647
Mike Reed353196f2017-07-21 11:01:18 -0400648bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
649 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400650}
651
652bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
653 SkPixmap pm;
654 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
655}
656
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000657bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400658 SkPixmap pm;
659 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700660 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000661 }
662 return false;
663}
664
Matt Sarett03dd6d52017-01-23 12:15:09 -0500665bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000666 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000667 SkBaseDevice* device = this->getDevice();
668 if (!device) {
669 return false;
670 }
671
Matt Sarett03dd6d52017-01-23 12:15:09 -0500672 // This check gives us an early out and prevents generation ID churn on the surface.
673 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
674 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
675 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
676 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000677 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000678
Matt Sarett03dd6d52017-01-23 12:15:09 -0500679 // Tell our owning surface to bump its generation ID.
680 const bool completeOverwrite =
681 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700682 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700683
Matt Sarett03dd6d52017-01-23 12:15:09 -0500684 // This can still fail, most notably in the case of a invalid color type or alpha type
685 // conversion. We could pull those checks into this function and avoid the unnecessary
686 // generation ID bump. But then we would be performing those checks twice, since they
687 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400688 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000689}
reed@google.com51df9e32010-12-23 19:29:18 +0000690
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691//////////////////////////////////////////////////////////////////////////////
692
reed2ff1fce2014-12-11 07:07:37 -0800693void SkCanvas::checkForDeferredSave() {
694 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800695 this->doSave();
696 }
697}
698
reedf0090cb2014-11-26 08:55:51 -0800699int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800700#ifdef SK_DEBUG
701 int count = 0;
702 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
703 for (;;) {
704 const MCRec* rec = (const MCRec*)iter.next();
705 if (!rec) {
706 break;
707 }
708 count += 1 + rec->fDeferredSaveCount;
709 }
710 SkASSERT(count == fSaveCount);
711#endif
712 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800713}
714
715int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800716 fSaveCount += 1;
717 fMCRec->fDeferredSaveCount += 1;
718 return this->getSaveCount() - 1; // return our prev value
719}
720
721void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800722 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700723
724 SkASSERT(fMCRec->fDeferredSaveCount > 0);
725 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800726 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800727}
728
729void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800730 if (fMCRec->fDeferredSaveCount > 0) {
731 SkASSERT(fSaveCount > 1);
732 fSaveCount -= 1;
733 fMCRec->fDeferredSaveCount -= 1;
734 } else {
735 // check for underflow
736 if (fMCStack.count() > 1) {
737 this->willRestore();
738 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700739 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800740 this->internalRestore();
741 this->didRestore();
742 }
reedf0090cb2014-11-26 08:55:51 -0800743 }
744}
745
746void SkCanvas::restoreToCount(int count) {
747 // sanity check
748 if (count < 1) {
749 count = 1;
750 }
mtkleinf0f14112014-12-12 08:46:25 -0800751
reedf0090cb2014-11-26 08:55:51 -0800752 int n = this->getSaveCount() - count;
753 for (int i = 0; i < n; ++i) {
754 this->restore();
755 }
756}
757
reed2ff1fce2014-12-11 07:07:37 -0800758void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000759 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700760 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000762
Mike Reedc42a1cd2017-02-14 14:25:14 -0500763 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764}
765
reed4960eee2015-12-18 07:09:18 -0800766bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400767 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768}
769
reed4960eee2015-12-18 07:09:18 -0800770bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700771 SkIRect* intersection, const SkImageFilter* imageFilter) {
Michael Ludwigaa861a12019-07-19 10:13:47 -0400772 // clipRectBounds() is called to determine the input layer size needed for a given image filter.
773 // The coordinate space of the rectangle passed to filterBounds(kReverse) is meant to be in the
774 // filtering layer space. Here, 'clipBounds' is always in the true device space. When an image
775 // filter does not require a decomposed CTM matrix, the filter space and device space are the
776 // same. When it has been decomposed, we want the original image filter node to process the
777 // bounds in the layer space represented by the decomposed scale matrix. 'imageFilter' is no
778 // longer the original filter, but has the remainder matrix baked into it, and passing in the
779 // the true device clip bounds ensures that the matrix image filter provides a layer clip bounds
780 // to the original filter node (barring inflation from consecutive calls to mapRect). While
781 // initially counter-intuitive given the apparent inconsistency of coordinate spaces, always
782 // passing getDeviceClipBounds() to 'imageFilter' is correct.
783 // FIXME (michaelludwig) - When the remainder matrix is instead applied as a final draw, it will
784 // be important to more accurately calculate the clip bounds in the layer space for the original
785 // image filter (similar to how matrix image filter does it, but ideally without the inflation).
Mike Reed918e1442017-01-23 11:39:45 -0500786 SkIRect clipBounds = this->getDeviceClipBounds();
787 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000788 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000789 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000790
reed96e657d2015-03-10 17:30:07 -0700791 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
792
Robert Phillips12078432018-05-17 11:17:39 -0400793 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
794 // If the image filter DAG affects transparent black then we will need to render
795 // out to the clip bounds
796 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000797 }
Robert Phillips12078432018-05-17 11:17:39 -0400798
799 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700800 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700802 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400803 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400805 inputSaveLayerBounds = clipBounds;
806 }
807
808 if (imageFilter) {
809 // expand the clip bounds by the image filter DAG to include extra content that might
810 // be required by the image filters.
811 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
812 SkImageFilter::kReverse_MapDirection,
813 &inputSaveLayerBounds);
814 }
815
816 SkIRect clippedSaveLayerBounds;
817 if (bounds) {
818 // For better or for worse, user bounds currently act as a hard clip on the layer's
819 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
820 clippedSaveLayerBounds = inputSaveLayerBounds;
821 } else {
822 // If there are no user bounds, we don't want to artificially restrict the resulting
823 // layer bounds, so allow the expanded clip bounds free reign.
824 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800826
827 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400828 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800829 if (BoundsAffectsClip(saveLayerFlags)) {
830 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
831 fMCRec->fRasterClip.setEmpty();
832 fDeviceClipBounds.setEmpty();
833 }
834 return false;
835 }
Robert Phillips12078432018-05-17 11:17:39 -0400836 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000837
reed4960eee2015-12-18 07:09:18 -0800838 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700839 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400840 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
841 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000842 }
843
844 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400845 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000846 }
Robert Phillips12078432018-05-17 11:17:39 -0400847
junov@chromium.orga907ac32012-02-24 21:54:07 +0000848 return true;
849}
850
reed4960eee2015-12-18 07:09:18 -0800851int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
852 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000853}
854
Cary Clarke041e312018-03-06 13:00:52 -0500855int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700856 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400857 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
858 // no need for the layer (or any of the draws until the matching restore()
859 this->save();
860 this->clipRect({0,0,0,0});
861 } else {
862 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
863 fSaveCount += 1;
864 this->internalSaveLayer(rec, strategy);
865 }
reed4960eee2015-12-18 07:09:18 -0800866 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800867}
868
Mike Reed148b7fd2018-12-18 17:38:18 -0500869int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
870 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
871 // Assuming clips never expand, if the request bounds is outside of the current clip
872 // there is no need to copy/restore the area, so just devolve back to a regular save.
873 this->save();
874 } else {
875 bool doTheWork = this->onDoSaveBehind(bounds);
876 fSaveCount += 1;
877 this->internalSave();
878 if (doTheWork) {
879 this->internalSaveBehind(bounds);
880 }
881 }
882 return this->getSaveCount() - 1;
883}
884
reeda2217ef2016-07-20 06:04:34 -0700885void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500886 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500887 const SkMatrix& ctm) {
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400888 SkPaint p;
Michael Ludwig08b260c2019-05-17 11:21:53 -0400889 SkIRect snapBounds = SkIRect::MakeXYWH(dstOrigin.x() - src->getOrigin().x(),
890 dstOrigin.y() - src->getOrigin().y(),
891 dst->width(), dst->height());
892 int x = 0;
893 int y = 0;
894
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400895 if (filter) {
Michael Ludwig08b260c2019-05-17 11:21:53 -0400896 // Calculate expanded snap bounds
897 SkIRect newBounds = filter->filterBounds(
898 snapBounds, ctm, SkImageFilter::kReverse_MapDirection, &snapBounds);
899 // Must clamp to valid src since the filter or rotations may expand beyond what's readable
900 SkIRect srcR = SkIRect::MakeWH(src->width(), src->height());
901 if (!newBounds.intersect(srcR)) {
902 return;
903 }
904
905 x = newBounds.fLeft - snapBounds.fLeft;
906 y = newBounds.fTop - snapBounds.fTop;
907 snapBounds = newBounds;
908
909 SkMatrix localCTM;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400910 sk_sp<SkImageFilter> modifiedFilter = as_IFB(filter)->applyCTMForBackdrop(ctm, &localCTM);
Michael Ludwig08b260c2019-05-17 11:21:53 -0400911 // Account for the origin offset in the CTM
912 localCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
913
914 // In this case we always wrap the filter (even when it's the original) with 'localCTM'
915 // since there's no device CTM stack that provides it to the image filter context.
916 // FIXME skbug.com/9074 - once perspective is properly supported, drop the
917 // localCTM.hasPerspective condition from assert.
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400918 SkASSERT(localCTM.isScaleTranslate() || as_IFB(filter)->canHandleComplexCTM() ||
Michael Ludwig08b260c2019-05-17 11:21:53 -0400919 localCTM.hasPerspective());
920 p.setImageFilter(modifiedFilter->makeWithLocalMatrix(localCTM));
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400921 }
922
Michael Ludwig08b260c2019-05-17 11:21:53 -0400923 auto special = src->snapBackImage(snapBounds);
reeda2217ef2016-07-20 06:04:34 -0700924 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400925 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700926 }
robertphillips7354a4b2015-12-16 05:08:27 -0800927}
reed70ee31b2015-12-10 13:44:45 -0800928
Mike Reed25394292019-03-07 09:36:36 -0500929// This is shared by all backends, but contains raster-specific thoughts. Can we defer to the
930// device to perform this?
Mike Kleine083f7c2018-02-07 12:54:27 -0500931static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500932 // Need to force L32 for now if we have an image filter.
Mike Reed25394292019-03-07 09:36:36 -0500933 // If filters ever support other colortypes, e.g. F16, we can modify this check.
Mike Klein649fb732018-02-26 15:09:16 -0500934 if (paint && paint->getImageFilter()) {
Mike Reed25394292019-03-07 09:36:36 -0500935 // TODO: can we query the imagefilter, to see if it can handle floats (so we don't always
936 // use N32 when the layer itself was float)?
937 return SkImageInfo::MakeN32Premul(w, h, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800938 }
Mike Klein649fb732018-02-26 15:09:16 -0500939
940 SkColorType ct = prev.colorType();
941 if (prev.bytesPerPixel() <= 4) {
942 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
943 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
944 ct = kN32_SkColorType;
945 }
946 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800947}
948
reed4960eee2015-12-18 07:09:18 -0800949void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700950 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800951 const SkRect* bounds = rec.fBounds;
952 const SkPaint* paint = rec.fPaint;
953 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
954
Mike Reed5532c2a2019-02-23 12:00:32 -0500955 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
956 // regardless of any hint-rect from the caller. skbug.com/8783
957 if (rec.fBackdrop) {
958 bounds = nullptr;
959 }
960
reed8c30a812016-04-20 16:36:51 -0700961 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400962 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700963 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400964 MCRec* modifiedRec = nullptr;
Michael Ludwig08b260c2019-05-17 11:21:53 -0400965
reed8c30a812016-04-20 16:36:51 -0700966 /*
Michael Ludwig08b260c2019-05-17 11:21:53 -0400967 * Many ImageFilters (so far) do not (on their own) correctly handle matrices (CTM) that
968 * contain rotation/skew/etc. We rely on applyCTM to create a new image filter DAG as needed to
969 * accommodate this, but it requires update the CTM we use when drawing into the layer.
reed8c30a812016-04-20 16:36:51 -0700970 *
971 * 1. Stash off the current CTM
Michael Ludwig08b260c2019-05-17 11:21:53 -0400972 * 2. Apply the CTM to imagefilter, which decomposes it into simple and complex transforms
973 * if necessary.
974 * 3. Wack the CTM to be the remaining scale matrix and use the modified imagefilter, which
975 * is a MatrixImageFilter that contains the complex matrix.
reed8c30a812016-04-20 16:36:51 -0700976 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
Michael Ludwig08b260c2019-05-17 11:21:53 -0400977 * 5. During restore, the MatrixImageFilter automatically applies complex stage to the output
reed8c30a812016-04-20 16:36:51 -0700978 * of the original imagefilter, and draw that (via drawSprite)
979 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
980 *
981 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
982 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
983 */
Michael Ludwig08b260c2019-05-17 11:21:53 -0400984 if (imageFilter) {
985 SkMatrix modifiedCTM;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400986 sk_sp<SkImageFilter> modifiedFilter = as_IFB(imageFilter)->applyCTM(stashedMatrix,
987 &modifiedCTM);
988 if (as_IFB(modifiedFilter)->uniqueID() != as_IFB(imageFilter)->uniqueID()) {
Michael Ludwig08b260c2019-05-17 11:21:53 -0400989 // The original filter couldn't support the CTM entirely
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400990 SkASSERT(modifiedCTM.isScaleTranslate() || as_IFB(imageFilter)->canHandleComplexCTM());
Michael Ludwig08b260c2019-05-17 11:21:53 -0400991 modifiedRec = fMCRec;
992 this->internalSetMatrix(modifiedCTM);
993 SkPaint* p = lazyP.set(*paint);
994 p->setImageFilter(std::move(modifiedFilter));
995 imageFilter = p->getImageFilter();
996 paint = p;
997 }
998 // Else the filter didn't change, so modifiedCTM == stashedMatrix and there's nothing
999 // left to do since the stack already has that as the CTM.
reed8c30a812016-04-20 16:36:51 -07001000 }
reed8c30a812016-04-20 16:36:51 -07001001
junov@chromium.orga907ac32012-02-24 21:54:07 +00001002 // do this before we create the layer. We don't call the public save() since
1003 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001004 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001005
junov@chromium.orga907ac32012-02-24 21:54:07 +00001006 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001007 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001008 if (modifiedRec) {
1009 // In this case there will be no layer in which to stash the matrix so we need to
1010 // revert the prior MCRec to its earlier state.
1011 modifiedRec->fMatrix = stashedMatrix;
1012 }
reed2ff1fce2014-12-11 07:07:37 -08001013 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014 }
1015
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001016 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1017 // the clipRectBounds() call above?
1018 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001019 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001020 }
1021
reed8dc0ccb2015-03-20 06:32:52 -07001022 SkPixelGeometry geo = fProps.pixelGeometry();
1023 if (paint) {
reed76033be2015-03-14 10:54:31 -07001024 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001025 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001026 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001027 }
1028 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029
robertphillips5139e502016-07-19 05:10:40 -07001030 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001031 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001032 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001033 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001034 }
reedb2db8982014-11-13 12:41:02 -08001035
Mike Kleine083f7c2018-02-07 12:54:27 -05001036 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
Mike Reed1f3548c2019-07-12 12:53:11 -04001037 if (rec.fSaveLayerFlags & kF16ColorType) {
1038 info = info.makeColorType(kRGBA_F16_SkColorType);
1039 }
reed129ed1c2016-02-22 06:42:31 -08001040
Hal Canary704cd322016-11-07 14:13:52 -05001041 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001042 {
Florin Malita4571e492019-07-16 10:25:58 -04001043 SkASSERT(info.alphaType() != kOpaque_SkAlphaType);
reeddaa57bf2015-05-15 10:39:17 -07001044 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001045 const bool trackCoverage =
1046 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001047 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed910ca0f2018-04-25 13:04:05 -04001048 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001049 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001050 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1051 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001052 return;
reed61f501f2015-04-29 08:34:00 -07001053 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001054 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001055 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056
Mike Reedb43a3e02017-02-11 10:18:58 -05001057 // only have a "next" if this new layer doesn't affect the clip (rare)
1058 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059 fMCRec->fLayer = layer;
1060 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001061
Mike Reedc61abee2017-02-28 17:45:27 -05001062 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001063 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001064 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001065 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001066
Mike Reedc42a1cd2017-02-14 14:25:14 -05001067 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1068
1069 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1070 if (layer->fNext) {
1071 // need to punch a hole in the previous device, so we don't draw there, given that
1072 // the new top-layer will allow drawing to happen "below" it.
1073 SkRegion hole(ir);
1074 do {
1075 layer = layer->fNext;
1076 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1077 } while (layer->fNext);
1078 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001079}
1080
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001081int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001082 if (0xFF == alpha) {
1083 return this->saveLayer(bounds, nullptr);
1084 } else {
1085 SkPaint tmpPaint;
1086 tmpPaint.setAlpha(alpha);
1087 return this->saveLayer(bounds, &tmpPaint);
1088 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001089}
1090
Mike Reed148b7fd2018-12-18 17:38:18 -05001091void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1092 SkIRect devBounds;
1093 if (localBounds) {
1094 SkRect tmp;
1095 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1096 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1097 devBounds.setEmpty();
1098 }
1099 } else {
1100 devBounds = this->getDeviceClipBounds();
1101 }
1102 if (devBounds.isEmpty()) {
1103 return;
1104 }
1105
1106 SkBaseDevice* device = this->getTopDevice();
1107 if (nullptr == device) { // Do we still need this check???
1108 return;
1109 }
1110
1111 // need the bounds relative to the device itself
1112 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1113
1114 auto backImage = device->snapBackImage(devBounds);
1115 if (!backImage) {
1116 return;
1117 }
1118
1119 // we really need the save, so we can wack the fMCRec
1120 this->checkForDeferredSave();
1121
1122 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1123
1124 SkPaint paint;
1125 paint.setBlendMode(SkBlendMode::kClear);
Mike Reed9adc82c2019-04-23 10:28:13 -04001126 this->drawClippedToSaveBehind(paint);
Mike Reed148b7fd2018-12-18 17:38:18 -05001127}
1128
reed@android.com8a1c16f2008-12-17 15:59:43 +00001129void SkCanvas::internalRestore() {
1130 SkASSERT(fMCStack.count() != 0);
1131
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001132 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001133 DeviceCM* layer = fMCRec->fLayer; // may be null
1134 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001135 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001136
Mike Reed148b7fd2018-12-18 17:38:18 -05001137 // move this out before we do the actual restore
1138 auto backImage = std::move(fMCRec->fBackImage);
1139
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140 // now do the normal restore()
1141 fMCRec->~MCRec(); // balanced in save()
1142 fMCStack.pop_back();
1143 fMCRec = (MCRec*)fMCStack.back();
1144
Mike Reedc42a1cd2017-02-14 14:25:14 -05001145 if (fMCRec) {
1146 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1147 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001148
Mike Reed148b7fd2018-12-18 17:38:18 -05001149 if (backImage) {
1150 SkPaint paint;
1151 paint.setBlendMode(SkBlendMode::kDstOver);
1152 const int x = backImage->fLoc.x();
1153 const int y = backImage->fLoc.y();
1154 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1155 nullptr, SkMatrix::I());
1156 }
1157
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1159 since if we're being recorded, we don't want to record this (the
1160 recorder will have already recorded the restore).
1161 */
bsalomon49f085d2014-09-05 13:34:00 -07001162 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001163 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001164 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001165 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001166 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001167 layer->fPaint.get(),
1168 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001169 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001170 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001171 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001172 delete layer;
reedb679ca82015-04-07 04:40:48 -07001173 } else {
1174 // we're at the root
reeda499f902015-05-01 09:34:31 -07001175 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001176 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001177 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001178 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001179 }
msarettfbfa2582016-08-12 08:29:08 -07001180
1181 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001182 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001183 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1184 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001185}
1186
reede8f30622016-03-23 18:59:25 -07001187sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001188 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001189 props = &fProps;
1190 }
1191 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001192}
1193
reede8f30622016-03-23 18:59:25 -07001194sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001195 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001196 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001197}
1198
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001199SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001200 return this->onImageInfo();
1201}
1202
1203SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001204 SkBaseDevice* dev = this->getDevice();
1205 if (dev) {
1206 return dev->imageInfo();
1207 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001208 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001209 }
1210}
1211
brianosman898235c2016-04-06 07:38:23 -07001212bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001213 return this->onGetProps(props);
1214}
1215
1216bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001217 SkBaseDevice* dev = this->getDevice();
1218 if (dev) {
1219 if (props) {
1220 *props = fProps;
1221 }
1222 return true;
1223 } else {
1224 return false;
1225 }
1226}
1227
reed6ceeebd2016-03-09 14:26:26 -08001228bool SkCanvas::peekPixels(SkPixmap* pmap) {
1229 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001230}
1231
reed884e97c2015-05-26 11:31:54 -07001232bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001233 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001234 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001235}
1236
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001237void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001238 SkPixmap pmap;
1239 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001240 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001241 }
1242 if (info) {
1243 *info = pmap.info();
1244 }
1245 if (rowBytes) {
1246 *rowBytes = pmap.rowBytes();
1247 }
1248 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001249 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001250 }
reed884e97c2015-05-26 11:31:54 -07001251 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001252}
1253
reed884e97c2015-05-26 11:31:54 -07001254bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001255 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001256 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001257}
1258
reed@android.com8a1c16f2008-12-17 15:59:43 +00001259/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260
Mike Reed8bcd1282019-03-13 16:51:54 -04001261// In our current design/features, we should never have a layer (src) in a different colorspace
1262// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1263// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1264// colorspace.
1265static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1266 SkASSERT(src == dst);
1267}
1268
Florin Malita53f77bd2017-04-28 13:48:37 -04001269void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1270 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001272 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273 paint = &tmp;
1274 }
reed@google.com4b226022011-01-11 18:32:13 +00001275
Mike Reed38992392019-07-30 10:48:15 -04001276 DRAW_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001277
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001279 SkBaseDevice* dstDev = iter.fDevice;
Mike Reed8bcd1282019-03-13 16:51:54 -04001280 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1281 srcDev->imageInfo().colorSpace());
Mike Reed38992392019-07-30 10:48:15 -04001282 paint = &draw.paint();
reed@google.com76dd2772012-01-05 21:15:07 +00001283 SkImageFilter* filter = paint->getImageFilter();
1284 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001285 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001286 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1287 if (specialImage) {
Mike Reed8bcd1282019-03-13 16:51:54 -04001288 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1289 specialImage->getColorSpace());
Florin Malita53f77bd2017-04-28 13:48:37 -04001290 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1291 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001292 }
reed@google.com76dd2772012-01-05 21:15:07 +00001293 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001294 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001295 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296 }
reeda2217ef2016-07-20 06:04:34 -07001297
Mike Reed38992392019-07-30 10:48:15 -04001298 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299}
1300
reed32704672015-12-16 08:27:10 -08001301/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001302
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001303void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001304 if (dx || dy) {
1305 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001306 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001307
reedfe69b502016-09-12 06:31:48 -07001308 // Translate shouldn't affect the is-scale-translateness of the matrix.
1309 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001310
Mike Reedc42a1cd2017-02-14 14:25:14 -05001311 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001312
reedfe69b502016-09-12 06:31:48 -07001313 this->didTranslate(dx,dy);
1314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315}
1316
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001317void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001318 SkMatrix m;
1319 m.setScale(sx, sy);
1320 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321}
1322
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001323void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001324 SkMatrix m;
1325 m.setRotate(degrees);
1326 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327}
1328
bungeman7438bfc2016-07-12 15:01:19 -07001329void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1330 SkMatrix m;
1331 m.setRotate(degrees, px, py);
1332 this->concat(m);
1333}
1334
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001335void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001336 SkMatrix m;
1337 m.setSkew(sx, sy);
1338 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001339}
1340
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001341void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001342 if (matrix.isIdentity()) {
1343 return;
1344 }
1345
reed2ff1fce2014-12-11 07:07:37 -08001346 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001347 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001348 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001349
Mike Reed7627fa52017-02-08 10:07:53 -05001350 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001351
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001352 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001353}
1354
reed8c30a812016-04-20 16:36:51 -07001355void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001356 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001357 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001358
Mike Reedc42a1cd2017-02-14 14:25:14 -05001359 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001360}
1361
1362void SkCanvas::setMatrix(const SkMatrix& matrix) {
1363 this->checkForDeferredSave();
1364 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001365 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366}
1367
reed@android.com8a1c16f2008-12-17 15:59:43 +00001368void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001369 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001370}
1371
1372//////////////////////////////////////////////////////////////////////////////
1373
Mike Reedc1f77742016-12-09 09:00:50 -05001374void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001375 if (!rect.isFinite()) {
1376 return;
1377 }
reed2ff1fce2014-12-11 07:07:37 -08001378 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001379 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1380 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001381}
1382
Mike Reedc1f77742016-12-09 09:00:50 -05001383void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001384 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001385
Mike Reed7627fa52017-02-08 10:07:53 -05001386 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001387
reedc64eff52015-11-21 12:39:45 -08001388 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001389 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1390 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001391 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001392}
1393
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001394void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1395 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001396 if (fClipRestrictionRect.isEmpty()) {
1397 // we notify the device, but we *dont* resolve deferred saves (since we're just
1398 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001399 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001400 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001401 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001402 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001403 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001404 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001405 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1406 }
1407}
1408
Mike Reedc1f77742016-12-09 09:00:50 -05001409void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001410 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001411 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001412 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001413 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1414 } else {
1415 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001416 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001417}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001418
Mike Reedc1f77742016-12-09 09:00:50 -05001419void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001420 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001421
Brian Salomona3b45d42016-10-03 11:36:16 -04001422 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001423
Mike Reed7627fa52017-02-08 10:07:53 -05001424 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001425
Mike Reed20800c82017-11-15 16:09:04 -05001426 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1427 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001428 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001429}
1430
Mike Reedc1f77742016-12-09 09:00:50 -05001431void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001432 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001433 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001434
1435 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1436 SkRect r;
1437 if (path.isRect(&r)) {
1438 this->onClipRect(r, op, edgeStyle);
1439 return;
1440 }
1441 SkRRect rrect;
1442 if (path.isOval(&r)) {
1443 rrect.setOval(r);
1444 this->onClipRRect(rrect, op, edgeStyle);
1445 return;
1446 }
1447 if (path.isRRect(&rrect)) {
1448 this->onClipRRect(rrect, op, edgeStyle);
1449 return;
1450 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001451 }
robertphillips39f05382015-11-24 09:30:12 -08001452
1453 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001454}
1455
Mike Reedc1f77742016-12-09 09:00:50 -05001456void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001457 AutoValidateClip avc(this);
1458
Brian Salomona3b45d42016-10-03 11:36:16 -04001459 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001460
Mike Reed7627fa52017-02-08 10:07:53 -05001461 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462
Brian Salomona3b45d42016-10-03 11:36:16 -04001463 const SkPath* rasterClipPath = &path;
1464 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001465 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1466 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001467 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468}
1469
Mike Reedc1f77742016-12-09 09:00:50 -05001470void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001471 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001472 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001473}
1474
Mike Reedc1f77742016-12-09 09:00:50 -05001475void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001476 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001477
reed@google.com5c3d1472011-02-22 19:12:23 +00001478 AutoValidateClip avc(this);
1479
Mike Reed20800c82017-11-15 16:09:04 -05001480 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001481 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482}
1483
reed@google.com819c9212011-02-23 18:56:55 +00001484#ifdef SK_DEBUG
1485void SkCanvas::validateClip() const {
1486 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001487 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001488 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001489 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001490 return;
1491 }
reed@google.com819c9212011-02-23 18:56:55 +00001492}
1493#endif
1494
Mike Reeda1361362017-03-07 09:37:29 -05001495bool SkCanvas::androidFramework_isClipAA() const {
1496 bool containsAA = false;
1497
1498 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1499
1500 return containsAA;
1501}
1502
1503class RgnAccumulator {
1504 SkRegion* fRgn;
1505public:
1506 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1507 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1508 SkIPoint origin = device->getOrigin();
1509 if (origin.x() | origin.y()) {
1510 rgn->translate(origin.x(), origin.y());
1511 }
1512 fRgn->op(*rgn, SkRegion::kUnion_Op);
1513 }
1514};
1515
1516void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1517 RgnAccumulator accum(rgn);
1518 SkRegion tmp;
1519
1520 rgn->setEmpty();
1521 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001522}
1523
reed@google.com5c3d1472011-02-22 19:12:23 +00001524///////////////////////////////////////////////////////////////////////////////
1525
reed@google.com754de5f2014-02-24 19:38:20 +00001526bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001527 return fMCRec->fRasterClip.isEmpty();
1528
1529 // TODO: should we only use the conservative answer in a recording canvas?
1530#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001531 SkBaseDevice* dev = this->getTopDevice();
1532 // if no device we return true
1533 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001534#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001535}
1536
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001537bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001538 SkBaseDevice* dev = this->getTopDevice();
1539 // if no device we return false
Dave Tapuska7139f132019-08-15 09:22:11 -04001540 return dev && dev->onGetClipType() == SkBaseDevice::ClipType::kRect;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001541}
1542
msarettfbfa2582016-08-12 08:29:08 -07001543static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1544#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1545 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1546 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1547 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1548 return 0xF != _mm_movemask_ps(mask);
1549#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1550 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1551 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1552 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1553 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1554#else
1555 SkRect devRectAsRect;
1556 SkRect devClipAsRect;
1557 devRect.store(&devRectAsRect.fLeft);
1558 devClip.store(&devClipAsRect.fLeft);
1559 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1560#endif
1561}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001562
msarettfbfa2582016-08-12 08:29:08 -07001563// It's important for this function to not be inlined. Otherwise the compiler will share code
1564// between the fast path and the slow path, resulting in two slow paths.
1565static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1566 const SkMatrix& matrix) {
1567 SkRect deviceRect;
1568 matrix.mapRect(&deviceRect, src);
1569 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1570}
1571
1572bool SkCanvas::quickReject(const SkRect& src) const {
1573#ifdef SK_DEBUG
1574 // Verify that fDeviceClipBounds are set properly.
1575 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001576 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001577 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001578 } else {
msarettfbfa2582016-08-12 08:29:08 -07001579 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001580 }
msarettfbfa2582016-08-12 08:29:08 -07001581
msarett9637ea92016-08-18 14:03:30 -07001582 // Verify that fIsScaleTranslate is set properly.
1583 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001584#endif
1585
msarett9637ea92016-08-18 14:03:30 -07001586 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001587 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1588 }
1589
1590 // We inline the implementation of mapScaleTranslate() for the fast path.
1591 float sx = fMCRec->fMatrix.getScaleX();
1592 float sy = fMCRec->fMatrix.getScaleY();
1593 float tx = fMCRec->fMatrix.getTranslateX();
1594 float ty = fMCRec->fMatrix.getTranslateY();
1595 Sk4f scale(sx, sy, sx, sy);
1596 Sk4f trans(tx, ty, tx, ty);
1597
1598 // Apply matrix.
1599 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1600
1601 // Make sure left < right, top < bottom.
1602 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1603 Sk4f min = Sk4f::Min(ltrb, rblt);
1604 Sk4f max = Sk4f::Max(ltrb, rblt);
1605 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1606 // ARM this sequence generates the fastest (a single instruction).
1607 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1608
1609 // Check if the device rect is NaN or outside the clip.
1610 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611}
1612
reed@google.com3b3e8952012-08-16 20:53:31 +00001613bool SkCanvas::quickReject(const SkPath& path) const {
1614 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615}
1616
Mike Klein83c8dd92017-11-28 17:08:45 -05001617SkRect SkCanvas::getLocalClipBounds() const {
1618 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001619 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001620 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001621 }
1622
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001623 SkMatrix inverse;
1624 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001625 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001626 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001627 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001628
Mike Reed42e8c532017-01-23 14:09:13 -05001629 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001630 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001631 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001632
Mike Reedb57b9312018-04-23 12:12:54 -04001633 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001634 inverse.mapRect(&bounds, r);
1635 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001636}
1637
Mike Klein83c8dd92017-11-28 17:08:45 -05001638SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001639 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001640}
1641
reed@android.com8a1c16f2008-12-17 15:59:43 +00001642const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001643 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001644}
1645
Brian Osman11052242016-10-27 14:47:55 -04001646GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001647 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001648 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001649}
1650
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001651GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001652 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001653 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001654}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001655
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001656void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1657 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001658 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001659 if (outer.isEmpty()) {
1660 return;
1661 }
1662 if (inner.isEmpty()) {
1663 this->drawRRect(outer, paint);
1664 return;
1665 }
1666
1667 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001668 // be able to return ...
1669 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001670 //
1671 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001672 if (!outer.getBounds().contains(inner.getBounds())) {
1673 return;
1674 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001675
1676 this->onDrawDRRect(outer, inner, paint);
1677}
1678
reed41af9662015-01-05 07:49:08 -08001679void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001680 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001681 this->onDrawPaint(paint);
1682}
1683
1684void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001685 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001686 // To avoid redundant logic in our culling code and various backends, we always sort rects
1687 // before passing them along.
1688 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001689}
1690
Mike Reedd5674082019-04-19 15:00:47 -04001691void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1692 TRACE_EVENT0("skia", TRACE_FUNC);
1693 this->onDrawBehind(paint);
1694}
1695
msarettdca352e2016-08-26 06:37:45 -07001696void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001697 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001698 if (region.isEmpty()) {
1699 return;
1700 }
1701
1702 if (region.isRect()) {
1703 return this->drawIRect(region.getBounds(), paint);
1704 }
1705
1706 this->onDrawRegion(region, paint);
1707}
1708
reed41af9662015-01-05 07:49:08 -08001709void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001710 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001711 // To avoid redundant logic in our culling code and various backends, we always sort rects
1712 // before passing them along.
1713 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001714}
1715
1716void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001717 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001718 this->onDrawRRect(rrect, paint);
1719}
1720
1721void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001722 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001723 this->onDrawPoints(mode, count, pts, paint);
1724}
1725
Mike Reede88a1cb2017-03-17 09:50:46 -04001726void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1727 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001728 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001729 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001730 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1731 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001732 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001733}
1734
1735void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001736 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001737 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001738 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1739}
1740
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001741void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1742 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001743 TRACE_EVENT0("skia", TRACE_FUNC);
1744 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001745 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001746 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1747}
1748
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001749void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1750 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001751 TRACE_EVENT0("skia", TRACE_FUNC);
1752 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001753 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001754 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001755}
1756
1757void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001758 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001759 this->onDrawPath(path, paint);
1760}
1761
reeda85d4d02015-05-06 12:56:48 -07001762void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001763 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001764 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001765 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001766}
1767
Mike Reedc4e31092018-01-30 11:15:27 -05001768// Returns true if the rect can be "filled" : non-empty and finite
1769static bool fillable(const SkRect& r) {
1770 SkScalar w = r.width();
1771 SkScalar h = r.height();
1772 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1773}
1774
reede47829b2015-08-06 10:02:53 -07001775void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1776 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001777 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001778 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001779 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001780 return;
1781 }
1782 this->onDrawImageRect(image, &src, dst, paint, constraint);
1783}
reed41af9662015-01-05 07:49:08 -08001784
reed84984ef2015-07-17 07:09:43 -07001785void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1786 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001787 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001788 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001789}
1790
Brian Salomonf08002c2018-10-26 16:15:46 -04001791void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001792 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001793 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001794 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001795}
reede47829b2015-08-06 10:02:53 -07001796
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001797namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001798class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001799public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001800 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1801 if (!origPaint) {
1802 return;
1803 }
1804 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1805 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1806 }
1807 if (origPaint->getMaskFilter()) {
1808 fPaint.writable()->setMaskFilter(nullptr);
1809 }
1810 if (origPaint->isAntiAlias()) {
1811 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001812 }
1813 }
1814
1815 const SkPaint* get() const {
1816 return fPaint;
1817 }
1818
1819private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001820 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001821};
1822} // namespace
1823
reed4c21dc52015-06-25 12:32:03 -07001824void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1825 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001826 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001827 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001828 if (dst.isEmpty()) {
1829 return;
1830 }
msarett552bca92016-08-03 06:53:26 -07001831 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001832 LatticePaint latticePaint(paint);
1833 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001834 } else {
reede47829b2015-08-06 10:02:53 -07001835 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001836 }
reed4c21dc52015-06-25 12:32:03 -07001837}
1838
msarett16882062016-08-16 09:31:08 -07001839void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1840 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001841 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001842 RETURN_ON_NULL(image);
1843 if (dst.isEmpty()) {
1844 return;
1845 }
msarett71df2d72016-09-30 12:41:42 -07001846
1847 SkIRect bounds;
1848 Lattice latticePlusBounds = lattice;
1849 if (!latticePlusBounds.fBounds) {
1850 bounds = SkIRect::MakeWH(image->width(), image->height());
1851 latticePlusBounds.fBounds = &bounds;
1852 }
1853
1854 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001855 LatticePaint latticePaint(paint);
1856 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001857 } else {
1858 this->drawImageRect(image, dst, paint);
1859 }
1860}
1861
reed41af9662015-01-05 07:49:08 -08001862void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001863 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001864 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001865 return;
1866 }
reed41af9662015-01-05 07:49:08 -08001867 this->onDrawBitmap(bitmap, dx, dy, paint);
1868}
1869
reede47829b2015-08-06 10:02:53 -07001870void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001871 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001872 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001873 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001874 return;
1875 }
reede47829b2015-08-06 10:02:53 -07001876 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001877}
1878
reed84984ef2015-07-17 07:09:43 -07001879void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1880 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001881 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001882}
1883
reede47829b2015-08-06 10:02:53 -07001884void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1885 SrcRectConstraint constraint) {
1886 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1887 constraint);
1888}
reede47829b2015-08-06 10:02:53 -07001889
reed41af9662015-01-05 07:49:08 -08001890void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1891 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001892 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001893 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001894 return;
1895 }
msarett552bca92016-08-03 06:53:26 -07001896 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001897 LatticePaint latticePaint(paint);
1898 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001899 } else {
reeda5517e22015-07-14 10:54:12 -07001900 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001901 }
reed41af9662015-01-05 07:49:08 -08001902}
1903
msarettc573a402016-08-02 08:05:56 -07001904void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1905 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001906 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001907 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001908 return;
1909 }
msarett71df2d72016-09-30 12:41:42 -07001910
1911 SkIRect bounds;
1912 Lattice latticePlusBounds = lattice;
1913 if (!latticePlusBounds.fBounds) {
1914 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1915 latticePlusBounds.fBounds = &bounds;
1916 }
1917
1918 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001919 LatticePaint latticePaint(paint);
1920 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001921 } else {
msarett16882062016-08-16 09:31:08 -07001922 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001923 }
msarettc573a402016-08-02 08:05:56 -07001924}
1925
reed71c3c762015-06-24 10:29:17 -07001926void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001927 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001928 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001929 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001930 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001931 if (count <= 0) {
1932 return;
1933 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001934 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001935 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001936 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001937}
1938
reedf70b5312016-03-04 16:36:20 -08001939void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001940 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001941 if (key) {
1942 this->onDrawAnnotation(rect, key, value);
1943 }
1944}
1945
reede47829b2015-08-06 10:02:53 -07001946void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1947 const SkPaint* paint, SrcRectConstraint constraint) {
1948 if (src) {
1949 this->drawImageRect(image, *src, dst, paint, constraint);
1950 } else {
1951 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1952 dst, paint, constraint);
1953 }
1954}
1955void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1956 const SkPaint* paint, SrcRectConstraint constraint) {
1957 if (src) {
1958 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1959 } else {
1960 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1961 dst, paint, constraint);
1962 }
1963}
1964
Mike Reed4204da22017-05-17 08:53:36 -04001965void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001966 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001967 this->onDrawShadowRec(path, rec);
1968}
1969
1970void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1971 SkPaint paint;
1972 const SkRect& pathBounds = path.getBounds();
1973
Mike Reed38992392019-07-30 10:48:15 -04001974 DRAW_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001975 while (iter.next()) {
1976 iter.fDevice->drawShadow(path, rec);
1977 }
Mike Reed38992392019-07-30 10:48:15 -04001978 DRAW_END
Mike Reed4204da22017-05-17 08:53:36 -04001979}
1980
Michael Ludwig390f0cc2019-03-19 09:16:38 -04001981void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
1982 QuadAAFlags aaFlags, SkColor color, SkBlendMode mode) {
1983 TRACE_EVENT0("skia", TRACE_FUNC);
1984 // Make sure the rect is sorted before passing it along
1985 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
1986}
1987
1988void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
1989 const SkPoint dstClips[],
1990 const SkMatrix preViewMatrices[],
1991 const SkPaint* paint,
1992 SrcRectConstraint constraint) {
1993 TRACE_EVENT0("skia", TRACE_FUNC);
1994 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
1995}
1996
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997//////////////////////////////////////////////////////////////////////////////
1998// These are the virtual drawing methods
1999//////////////////////////////////////////////////////////////////////////////
2000
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002001void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002002 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002003 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2004 }
2005}
2006
reed41af9662015-01-05 07:49:08 -08002007void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002008 this->internalDrawPaint(paint);
2009}
2010
2011void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Mike Reed38992392019-07-30 10:48:15 -04002012 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002013
2014 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002015 iter.fDevice->drawPaint(draw.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002016 }
2017
Mike Reed38992392019-07-30 10:48:15 -04002018 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002019}
2020
reed41af9662015-01-05 07:49:08 -08002021void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2022 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002023 if ((long)count <= 0) {
2024 return;
2025 }
2026
Mike Reed822128b2017-02-28 16:41:03 -05002027 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002028 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002029 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002030 // special-case 2 points (common for drawing a single line)
2031 if (2 == count) {
2032 r.set(pts[0], pts[1]);
2033 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002034 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002035 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002036 if (!r.isFinite()) {
2037 return;
2038 }
Mike Reed822128b2017-02-28 16:41:03 -05002039 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002040 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2041 return;
2042 }
2043 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002044 }
reed@google.coma584aed2012-05-16 14:06:02 +00002045
halcanary96fcdcc2015-08-27 07:41:13 -07002046 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002047
Mike Reed38992392019-07-30 10:48:15 -04002048 DRAW_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002049
reed@android.com8a1c16f2008-12-17 15:59:43 +00002050 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002051 iter.fDevice->drawPoints(mode, count, pts, draw.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002052 }
reed@google.com4b226022011-01-11 18:32:13 +00002053
Mike Reed38992392019-07-30 10:48:15 -04002054 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002055}
2056
reed4a167172016-08-18 17:15:25 -07002057static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
Mike Reed9dc0b9e2019-07-29 17:52:48 -04002058 return paint.getImageFilter() != nullptr;
reed4a167172016-08-18 17:15:25 -07002059}
2060
reed41af9662015-01-05 07:49:08 -08002061void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002062 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002063 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002064 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002065 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002066 return;
2067 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002068 }
reed@google.com4b226022011-01-11 18:32:13 +00002069
reed4a167172016-08-18 17:15:25 -07002070 if (needs_autodrawlooper(this, paint)) {
Mike Reed38992392019-07-30 10:48:15 -04002071 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002072
reed4a167172016-08-18 17:15:25 -07002073 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002074 iter.fDevice->drawRect(r, draw.paint());
reed4a167172016-08-18 17:15:25 -07002075 }
2076
Mike Reed38992392019-07-30 10:48:15 -04002077 DRAW_END
Mike Reed49f8da02018-08-27 10:48:52 -04002078 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002079 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002080 SkDrawIter iter(this);
2081 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002082 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002083 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002084 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002085}
2086
msarett44df6512016-08-25 13:54:30 -07002087void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002088 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002089 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002090 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002091 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2092 return;
2093 }
msarett44df6512016-08-25 13:54:30 -07002094 }
2095
Mike Reed38992392019-07-30 10:48:15 -04002096 DRAW_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002097
2098 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002099 iter.fDevice->drawRegion(region, draw.paint());
msarett44df6512016-08-25 13:54:30 -07002100 }
2101
Mike Reed38992392019-07-30 10:48:15 -04002102 DRAW_END
msarett44df6512016-08-25 13:54:30 -07002103}
2104
Mike Reedd5674082019-04-19 15:00:47 -04002105void SkCanvas::onDrawBehind(const SkPaint& paint) {
2106 SkIRect bounds;
2107 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2108 for (;;) {
2109 const MCRec* rec = (const MCRec*)iter.prev();
2110 if (!rec) {
2111 return; // no backimages, so nothing to draw
2112 }
2113 if (rec->fBackImage) {
2114 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2115 rec->fBackImage->fImage->width(),
2116 rec->fBackImage->fImage->height());
2117 break;
2118 }
2119 }
2120
Mike Reed38992392019-07-30 10:48:15 -04002121 DRAW_BEGIN(paint, nullptr)
Mike Reedd5674082019-04-19 15:00:47 -04002122
2123 while (iter.next()) {
2124 SkBaseDevice* dev = iter.fDevice;
2125
Mike Reedd5674082019-04-19 15:00:47 -04002126 dev->save();
2127 // We use clipRegion because it is already defined to operate in dev-space
2128 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2129 // but we don't want that, so we undo that before calling in.
2130 SkRegion rgn(bounds.makeOffset(dev->fOrigin.fX, dev->fOrigin.fY));
2131 dev->clipRegion(rgn, SkClipOp::kIntersect);
Mike Reed38992392019-07-30 10:48:15 -04002132 dev->drawPaint(draw.paint());
Mike Reed9adc82c2019-04-23 10:28:13 -04002133 dev->restore(fMCRec->fMatrix);
Mike Reedd5674082019-04-19 15:00:47 -04002134 }
2135
Mike Reed38992392019-07-30 10:48:15 -04002136 DRAW_END
Mike Reedd5674082019-04-19 15:00:47 -04002137}
2138
reed41af9662015-01-05 07:49:08 -08002139void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002140 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002141 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002142 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002143 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002144 return;
2145 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002146 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002147
Mike Reed38992392019-07-30 10:48:15 -04002148 DRAW_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002149
2150 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002151 iter.fDevice->drawOval(oval, draw.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002152 }
2153
Mike Reed38992392019-07-30 10:48:15 -04002154 DRAW_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002155}
2156
bsalomonac3aa242016-08-19 11:25:19 -07002157void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2158 SkScalar sweepAngle, bool useCenter,
2159 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002160 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002161 if (paint.canComputeFastBounds()) {
2162 SkRect storage;
2163 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002164 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002165 return;
2166 }
bsalomonac3aa242016-08-19 11:25:19 -07002167 }
2168
Mike Reed38992392019-07-30 10:48:15 -04002169 DRAW_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002170
2171 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002172 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, draw.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002173 }
2174
Mike Reed38992392019-07-30 10:48:15 -04002175 DRAW_END
bsalomonac3aa242016-08-19 11:25:19 -07002176}
2177
reed41af9662015-01-05 07:49:08 -08002178void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002179 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002180 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002181 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2182 return;
2183 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002184 }
2185
2186 if (rrect.isRect()) {
2187 // call the non-virtual version
2188 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002189 return;
2190 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002191 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002192 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2193 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002194 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002195
Mike Reed38992392019-07-30 10:48:15 -04002196 DRAW_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002197
2198 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002199 iter.fDevice->drawRRect(rrect, draw.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002200 }
2201
Mike Reed38992392019-07-30 10:48:15 -04002202 DRAW_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002203}
2204
Mike Reed822128b2017-02-28 16:41:03 -05002205void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002206 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002207 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002208 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2209 return;
2210 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002211 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002212
Mike Reed38992392019-07-30 10:48:15 -04002213 DRAW_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002214
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002215 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002216 iter.fDevice->drawDRRect(outer, inner, draw.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002217 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002218
Mike Reed38992392019-07-30 10:48:15 -04002219 DRAW_END
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002220}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002221
reed41af9662015-01-05 07:49:08 -08002222void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002223 if (!path.isFinite()) {
2224 return;
2225 }
2226
Mike Reed822128b2017-02-28 16:41:03 -05002227 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002228 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002229 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002230 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2231 return;
2232 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002233 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002234
Mike Reed822128b2017-02-28 16:41:03 -05002235 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002236 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002237 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002238 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002239 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002240 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002241
Mike Reed38992392019-07-30 10:48:15 -04002242 DRAW_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002243
2244 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002245 iter.fDevice->drawPath(path, draw.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002246 }
2247
Mike Reed38992392019-07-30 10:48:15 -04002248 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002249}
2250
reed262a71b2015-12-05 13:07:27 -08002251bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002252 if (!paint.getImageFilter()) {
2253 return false;
2254 }
2255
2256 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002257 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002258 return false;
2259 }
2260
2261 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2262 // Once we can filter and the filter will return a result larger than itself, we should be
2263 // able to remove this constraint.
2264 // skbug.com/4526
2265 //
2266 SkPoint pt;
2267 ctm.mapXY(x, y, &pt);
2268 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2269 return ir.contains(fMCRec->fRasterClip.getBounds());
2270}
2271
Mike Reedf441cfc2018-04-11 14:50:16 -04002272// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2273// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2274// null.
2275static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2276 if (paintParam) {
2277 *real = *paintParam;
2278 real->setStyle(SkPaint::kFill_Style);
2279 real->setPathEffect(nullptr);
2280 paintParam = real;
2281 }
2282 return paintParam;
2283}
2284
reeda85d4d02015-05-06 12:56:48 -07002285void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002286 SkPaint realPaint;
2287 paint = init_image_paint(&realPaint, paint);
2288
reeda85d4d02015-05-06 12:56:48 -07002289 SkRect bounds = SkRect::MakeXYWH(x, y,
2290 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002291 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002292 SkRect tmp = bounds;
2293 if (paint) {
2294 paint->computeFastBounds(tmp, &tmp);
2295 }
2296 if (this->quickReject(tmp)) {
2297 return;
2298 }
reeda85d4d02015-05-06 12:56:48 -07002299 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002300 // At this point we need a real paint object. If the caller passed null, then we should
2301 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2302 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2303 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002304
reeda2217ef2016-07-20 06:04:34 -07002305 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002306 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2307 *paint);
2308 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002309 special = this->getDevice()->makeSpecial(image);
2310 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002311 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002312 }
2313 }
2314
Mike Reed38992392019-07-30 10:48:15 -04002315 DRAW_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed262a71b2015-12-05 13:07:27 -08002316
reeda85d4d02015-05-06 12:56:48 -07002317 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002318 const SkPaint& pnt = draw.paint();
reeda2217ef2016-07-20 06:04:34 -07002319 if (special) {
2320 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002321 iter.fDevice->ctm().mapXY(x, y, &pt);
2322 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002323 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002324 SkScalarRoundToInt(pt.fY), pnt,
2325 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002326 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002327 iter.fDevice->drawImageRect(
2328 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2329 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002330 }
reeda85d4d02015-05-06 12:56:48 -07002331 }
halcanary9d524f22016-03-29 09:03:52 -07002332
Mike Reed38992392019-07-30 10:48:15 -04002333 DRAW_END
piotaixrb5fae932014-09-24 13:03:30 -07002334}
2335
reed41af9662015-01-05 07:49:08 -08002336void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002337 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002338 SkPaint realPaint;
2339 paint = init_image_paint(&realPaint, paint);
2340
halcanary96fcdcc2015-08-27 07:41:13 -07002341 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002342 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002343 if (paint) {
2344 paint->computeFastBounds(dst, &storage);
2345 }
2346 if (this->quickReject(storage)) {
2347 return;
2348 }
reeda85d4d02015-05-06 12:56:48 -07002349 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002350 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002351
Mike Reed38992392019-07-30 10:48:15 -04002352 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002353
reeda85d4d02015-05-06 12:56:48 -07002354 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002355 iter.fDevice->drawImageRect(image, src, dst, draw.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002356 }
halcanary9d524f22016-03-29 09:03:52 -07002357
Mike Reed38992392019-07-30 10:48:15 -04002358 DRAW_END
piotaixrb5fae932014-09-24 13:03:30 -07002359}
2360
reed41af9662015-01-05 07:49:08 -08002361void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002362 SkDEBUGCODE(bitmap.validate();)
2363
reed33366972015-10-08 09:22:02 -07002364 if (bitmap.drawsNothing()) {
2365 return;
2366 }
2367
Mike Reedf441cfc2018-04-11 14:50:16 -04002368 SkPaint realPaint;
2369 init_image_paint(&realPaint, paint);
2370 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002371
Mike Reed822128b2017-02-28 16:41:03 -05002372 SkRect bounds;
2373 bitmap.getBounds(&bounds);
2374 bounds.offset(x, y);
2375 bool canFastBounds = paint->canComputeFastBounds();
2376 if (canFastBounds) {
2377 SkRect storage;
2378 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002379 return;
2380 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002381 }
reed@google.com4b226022011-01-11 18:32:13 +00002382
reeda2217ef2016-07-20 06:04:34 -07002383 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002384 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2385 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002386 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002387 special = this->getDevice()->makeSpecial(bitmap);
2388 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002389 drawAsSprite = false;
2390 }
2391 }
2392
Mike Reed38992392019-07-30 10:48:15 -04002393 DRAW_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002394
2395 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002396 const SkPaint& pnt = draw.paint();
reeda2217ef2016-07-20 06:04:34 -07002397 if (special) {
reed262a71b2015-12-05 13:07:27 -08002398 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002399 iter.fDevice->ctm().mapXY(x, y, &pt);
2400 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002401 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002402 SkScalarRoundToInt(pt.fY), pnt,
2403 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002404 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002405 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2406 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2407 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002408 }
reed33366972015-10-08 09:22:02 -07002409 }
msarettfbfa2582016-08-12 08:29:08 -07002410
Mike Reed38992392019-07-30 10:48:15 -04002411 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002412}
2413
reed@google.com9987ec32011-09-07 11:57:52 +00002414// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002415void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002416 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002417 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002418 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002419 return;
2420 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002421
halcanary96fcdcc2015-08-27 07:41:13 -07002422 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002423 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002424 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2425 return;
2426 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002427 }
reed@google.com3d608122011-11-21 15:16:16 +00002428
reed@google.com33535f32012-09-25 15:37:50 +00002429 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002430 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002431 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002432 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002433
Mike Reed38992392019-07-30 10:48:15 -04002434 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002435
reed@google.com33535f32012-09-25 15:37:50 +00002436 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002437 iter.fDevice->drawBitmapRect(bitmap, src, dst, draw.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002438 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002439
Mike Reed38992392019-07-30 10:48:15 -04002440 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002441}
2442
reed41af9662015-01-05 07:49:08 -08002443void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002444 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002445 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002446 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002447}
2448
reed4c21dc52015-06-25 12:32:03 -07002449void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2450 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002451 SkPaint realPaint;
2452 paint = init_image_paint(&realPaint, paint);
2453
halcanary96fcdcc2015-08-27 07:41:13 -07002454 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002455 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002456 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2457 return;
2458 }
reed@google.com3d608122011-11-21 15:16:16 +00002459 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002460 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002461
Mike Reed38992392019-07-30 10:48:15 -04002462 DRAW_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002463
reed4c21dc52015-06-25 12:32:03 -07002464 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002465 iter.fDevice->drawImageNine(image, center, dst, draw.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002466 }
halcanary9d524f22016-03-29 09:03:52 -07002467
Mike Reed38992392019-07-30 10:48:15 -04002468 DRAW_END
reed@google.com9987ec32011-09-07 11:57:52 +00002469}
2470
reed41af9662015-01-05 07:49:08 -08002471void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2472 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002473 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002474 SkPaint realPaint;
2475 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002476
halcanary96fcdcc2015-08-27 07:41:13 -07002477 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002478 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002479 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2480 return;
2481 }
reed4c21dc52015-06-25 12:32:03 -07002482 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002483 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002484
Mike Reed38992392019-07-30 10:48:15 -04002485 DRAW_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002486
reed4c21dc52015-06-25 12:32:03 -07002487 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002488 iter.fDevice->drawBitmapNine(bitmap, center, dst, draw.paint());
reed4c21dc52015-06-25 12:32:03 -07002489 }
halcanary9d524f22016-03-29 09:03:52 -07002490
Mike Reed38992392019-07-30 10:48:15 -04002491 DRAW_END
reed@google.com9987ec32011-09-07 11:57:52 +00002492}
2493
msarett16882062016-08-16 09:31:08 -07002494void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2495 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002496 SkPaint realPaint;
2497 paint = init_image_paint(&realPaint, paint);
2498
msarett16882062016-08-16 09:31:08 -07002499 if (nullptr == paint || paint->canComputeFastBounds()) {
2500 SkRect storage;
2501 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2502 return;
2503 }
2504 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002505 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002506
Mike Reed38992392019-07-30 10:48:15 -04002507 DRAW_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002508
2509 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002510 iter.fDevice->drawImageLattice(image, lattice, dst, draw.paint());
msarett16882062016-08-16 09:31:08 -07002511 }
2512
Mike Reed38992392019-07-30 10:48:15 -04002513 DRAW_END
msarett16882062016-08-16 09:31:08 -07002514}
2515
2516void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2517 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002518 SkPaint realPaint;
2519 paint = init_image_paint(&realPaint, paint);
2520
msarett16882062016-08-16 09:31:08 -07002521 if (nullptr == paint || paint->canComputeFastBounds()) {
2522 SkRect storage;
2523 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2524 return;
2525 }
2526 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002527 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002528
Mike Reed38992392019-07-30 10:48:15 -04002529 DRAW_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002530
2531 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002532 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, draw.paint());
msarett16882062016-08-16 09:31:08 -07002533 }
2534
Mike Reed38992392019-07-30 10:48:15 -04002535 DRAW_END
msarett16882062016-08-16 09:31:08 -07002536}
2537
fmalita00d5c2c2014-08-21 08:53:26 -07002538void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2539 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002540 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002541 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002542 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002543 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002544 SkRect tmp;
2545 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2546 return;
2547 }
2548 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002549 }
2550
fmalita024f9962015-03-03 19:08:17 -08002551 // We cannot filter in the looper as we normally do, because the paint is
2552 // incomplete at this point (text-related attributes are embedded within blob run paints).
Mike Reed38992392019-07-30 10:48:15 -04002553 DRAW_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002554
fmalitaaa1b9122014-08-28 14:32:24 -07002555 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002556 fScratchGlyphRunBuilder->drawTextBlob(draw.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002557 }
2558
Mike Reed38992392019-07-30 10:48:15 -04002559 DRAW_END
fmalita00d5c2c2014-08-21 08:53:26 -07002560}
2561
Mike Reed358fcad2018-11-23 15:27:51 -05002562// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002563void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002564 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2565 TRACE_EVENT0("skia", TRACE_FUNC);
2566 if (byteLength) {
2567 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002568 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002569 }
2570}
Mike Reed4f81bb72019-01-23 09:23:00 -05002571
fmalita00d5c2c2014-08-21 08:53:26 -07002572void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2573 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002574 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002575 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002576 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002577 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002578}
reed@google.come0d9ce82014-04-23 04:00:17 +00002579
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002580void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002581 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Mike Reed38992392019-07-30 10:48:15 -04002582 DRAW_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002583
2584 while (iter.next()) {
2585 // In the common case of one iteration we could std::move vertices here.
Mike Reed38992392019-07-30 10:48:15 -04002586 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, draw.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002587 }
2588
Mike Reed38992392019-07-30 10:48:15 -04002589 DRAW_END
Brian Salomon199fb872017-02-06 09:41:10 -05002590}
2591
dandovb3c9d1c2014-08-12 08:34:29 -07002592void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002593 const SkPoint texCoords[4], SkBlendMode bmode,
2594 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002595 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002596 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002597 return;
2598 }
mtklein6cfa73a2014-08-13 13:33:49 -07002599
Mike Reedfaba3712016-11-03 14:45:31 -04002600 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002601}
2602
2603void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002604 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002605 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002606 // Since a patch is always within the convex hull of the control points, we discard it when its
2607 // bounding rectangle is completely outside the current clip.
2608 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002609 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002610 if (this->quickReject(bounds)) {
2611 return;
2612 }
mtklein6cfa73a2014-08-13 13:33:49 -07002613
Mike Reed38992392019-07-30 10:48:15 -04002614 DRAW_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002615
dandovecfff212014-08-04 10:02:00 -07002616 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002617 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002618 }
mtklein6cfa73a2014-08-13 13:33:49 -07002619
Mike Reed38992392019-07-30 10:48:15 -04002620 DRAW_END
dandovecfff212014-08-04 10:02:00 -07002621}
2622
reeda8db7282015-07-07 10:22:31 -07002623void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002624#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002625 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002626#endif
reede3b38ce2016-01-08 09:18:44 -08002627 RETURN_ON_NULL(dr);
2628 if (x || y) {
2629 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2630 this->onDrawDrawable(dr, &matrix);
2631 } else {
2632 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002633 }
2634}
2635
reeda8db7282015-07-07 10:22:31 -07002636void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002637#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002638 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002639#endif
reede3b38ce2016-01-08 09:18:44 -08002640 RETURN_ON_NULL(dr);
2641 if (matrix && matrix->isIdentity()) {
2642 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002643 }
reede3b38ce2016-01-08 09:18:44 -08002644 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002645}
2646
2647void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002648 // drawable bounds are no longer reliable (e.g. android displaylist)
2649 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002650 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002651}
2652
reed71c3c762015-06-24 10:29:17 -07002653void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002654 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002655 const SkRect* cull, const SkPaint* paint) {
2656 if (cull && this->quickReject(*cull)) {
2657 return;
2658 }
2659
2660 SkPaint pnt;
2661 if (paint) {
2662 pnt = *paint;
2663 }
halcanary9d524f22016-03-29 09:03:52 -07002664
Mike Reed38992392019-07-30 10:48:15 -04002665 DRAW_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002666 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002667 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002668 }
Mike Reed38992392019-07-30 10:48:15 -04002669 DRAW_END
reed71c3c762015-06-24 10:29:17 -07002670}
2671
reedf70b5312016-03-04 16:36:20 -08002672void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2673 SkASSERT(key);
2674
2675 SkPaint paint;
Mike Reed38992392019-07-30 10:48:15 -04002676 DRAW_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002677 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002678 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002679 }
Mike Reed38992392019-07-30 10:48:15 -04002680 DRAW_END
reedf70b5312016-03-04 16:36:20 -08002681}
2682
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002683void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2684 SkColor color, SkBlendMode mode) {
2685 SkASSERT(r.isSorted());
2686
2687 // If this used a paint, it would be a filled color with blend mode, which does not
2688 // need to use an autodraw loop, so use SkDrawIter directly.
2689 if (this->quickReject(r)) {
2690 return;
2691 }
2692
2693 this->predrawNotify();
2694 SkDrawIter iter(this);
2695 while(iter.next()) {
2696 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2697 }
2698}
2699
2700void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2701 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2702 const SkPaint* paint, SrcRectConstraint constraint) {
2703 SkPaint realPaint;
2704 init_image_paint(&realPaint, paint);
2705
2706 // Looper is used when there are image filters, which drawEdgeAAImageSet needs to support
2707 // for Chromium's RenderPassDrawQuads' filters.
Mike Reed38992392019-07-30 10:48:15 -04002708 DRAW_BEGIN(realPaint, nullptr)
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002709 while (iter.next()) {
2710 iter.fDevice->drawEdgeAAImageSet(
Mike Reed38992392019-07-30 10:48:15 -04002711 imageSet, count, dstClips, preViewMatrices, draw.paint(), constraint);
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002712 }
Mike Reed38992392019-07-30 10:48:15 -04002713 DRAW_END
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002714}
2715
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716//////////////////////////////////////////////////////////////////////////////
2717// These methods are NOT virtual, and therefore must call back into virtual
2718// methods, rather than actually drawing themselves.
2719//////////////////////////////////////////////////////////////////////////////
2720
reed374772b2016-10-05 17:33:02 -07002721void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002722 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002724 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002725 this->drawPaint(paint);
2726}
2727
2728void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002729 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2731}
2732
Mike Reed3661bc92017-02-22 13:21:42 -05002733void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002734 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 pts[0].set(x0, y0);
2736 pts[1].set(x1, y1);
2737 this->drawPoints(kLines_PointMode, 2, pts, paint);
2738}
2739
Mike Reed3661bc92017-02-22 13:21:42 -05002740void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741 if (radius < 0) {
2742 radius = 0;
2743 }
2744
2745 SkRect r;
2746 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002747 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748}
2749
2750void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2751 const SkPaint& paint) {
2752 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002753 SkRRect rrect;
2754 rrect.setRectXY(r, rx, ry);
2755 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002756 } else {
2757 this->drawRect(r, paint);
2758 }
2759}
2760
reed@android.com8a1c16f2008-12-17 15:59:43 +00002761void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2762 SkScalar sweepAngle, bool useCenter,
2763 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002764 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002765 if (oval.isEmpty() || !sweepAngle) {
2766 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767 }
bsalomon21af9ca2016-08-25 12:29:23 -07002768 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769}
2770
reed@android.comf76bacf2009-05-13 14:00:33 +00002771///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002772#ifdef SK_DISABLE_SKPICTURE
2773void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002774
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002775
2776void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2777 const SkPaint* paint) {}
2778#else
Mike Klein88d90712018-01-27 17:30:04 +00002779/**
2780 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2781 * against the playback cost of recursing into the subpicture to get at its actual ops.
2782 *
2783 * For now we pick a conservatively small value, though measurement (and other heuristics like
2784 * the type of ops contained) may justify changing this value.
2785 */
2786#define kMaxPictureOpsToUnrollInsteadOfRef 1
2787
reedd5fa1a42014-08-09 11:08:05 -07002788void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002789 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002790 RETURN_ON_NULL(picture);
2791
reede3b38ce2016-01-08 09:18:44 -08002792 if (matrix && matrix->isIdentity()) {
2793 matrix = nullptr;
2794 }
Mike Klein88d90712018-01-27 17:30:04 +00002795 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2796 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2797 picture->playback(this);
2798 } else {
2799 this->onDrawPicture(picture, matrix, paint);
2800 }
reedd5fa1a42014-08-09 11:08:05 -07002801}
robertphillips9b14f262014-06-04 05:40:44 -07002802
reedd5fa1a42014-08-09 11:08:05 -07002803void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2804 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002805 if (!paint || paint->canComputeFastBounds()) {
2806 SkRect bounds = picture->cullRect();
2807 if (paint) {
2808 paint->computeFastBounds(bounds, &bounds);
2809 }
2810 if (matrix) {
2811 matrix->mapRect(&bounds);
2812 }
2813 if (this->quickReject(bounds)) {
2814 return;
2815 }
2816 }
2817
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002818 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002819 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002820}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002821#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002822
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823///////////////////////////////////////////////////////////////////////////////
2824///////////////////////////////////////////////////////////////////////////////
2825
reed3aafe112016-08-18 12:45:34 -07002826SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002827 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828
2829 SkASSERT(canvas);
2830
reed3aafe112016-08-18 12:45:34 -07002831 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002832 fDone = !fImpl->next();
2833}
2834
2835SkCanvas::LayerIter::~LayerIter() {
2836 fImpl->~SkDrawIter();
2837}
2838
2839void SkCanvas::LayerIter::next() {
2840 fDone = !fImpl->next();
2841}
2842
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002843SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002844 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002845}
2846
2847const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002848 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849}
2850
2851const SkPaint& SkCanvas::LayerIter::paint() const {
2852 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002853 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002854 paint = &fDefaultPaint;
2855 }
2856 return *paint;
2857}
2858
Mike Reedca37f322018-03-08 13:22:16 -05002859SkIRect SkCanvas::LayerIter::clipBounds() const {
2860 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002861}
2862
reed@android.com8a1c16f2008-12-17 15:59:43 +00002863int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2864int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002865
2866///////////////////////////////////////////////////////////////////////////////
2867
Brian Osmane8a98632019-04-10 10:26:10 -04002868SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2869SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2870SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2871SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2872
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002873SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2874 const SkRect& dstRect, int matrixIndex, float alpha,
2875 unsigned aaFlags, bool hasClip)
2876 : fImage(std::move(image))
2877 , fSrcRect(srcRect)
2878 , fDstRect(dstRect)
2879 , fMatrixIndex(matrixIndex)
2880 , fAlpha(alpha)
2881 , fAAFlags(aaFlags)
2882 , fHasClip(hasClip) {}
2883
2884SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2885 const SkRect& dstRect, float alpha, unsigned aaFlags)
2886 : fImage(std::move(image))
2887 , fSrcRect(srcRect)
2888 , fDstRect(dstRect)
2889 , fAlpha(alpha)
2890 , fAAFlags(aaFlags) {}
2891
2892///////////////////////////////////////////////////////////////////////////////
2893
Mike Reed5df49342016-11-12 08:06:55 -06002894std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002895 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002896 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002897 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002898 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002899
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002900 SkBitmap bitmap;
2901 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002902 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002903 }
Mike Reed12f77342017-11-08 11:19:52 -05002904
2905 return props ?
2906 skstd::make_unique<SkCanvas>(bitmap, *props) :
2907 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002908}
reedd5fa1a42014-08-09 11:08:05 -07002909
2910///////////////////////////////////////////////////////////////////////////////
2911
Florin Malitaee424ac2016-12-01 12:47:59 -05002912SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002913 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002914
Florin Malita439ace92016-12-02 12:05:41 -05002915SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002916 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002917
Herb Derbyefe39bc2018-05-01 17:06:20 -04002918SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002919 : INHERITED(device) {}
2920
Florin Malitaee424ac2016-12-01 12:47:59 -05002921SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2922 (void)this->INHERITED::getSaveLayerStrategy(rec);
2923 return kNoLayer_SaveLayerStrategy;
2924}
2925
Mike Reed148b7fd2018-12-18 17:38:18 -05002926bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2927 return false;
2928}
2929
Florin Malitaee424ac2016-12-01 12:47:59 -05002930///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002931
reed73603f32016-09-20 08:42:38 -07002932static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2933static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2934static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2935static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2936static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2937static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002938
2939///////////////////////////////////////////////////////////////////////////////////////////////////
2940
2941SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2942 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002943 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002944 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2945 SkIPoint origin = dev->getOrigin();
2946 SkMatrix ctm = this->getTotalMatrix();
2947 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2948
2949 SkIRect clip = fMCRec->fRasterClip.getBounds();
2950 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002951 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002952 clip.setEmpty();
2953 }
2954
2955 fAllocator->updateHandle(handle, ctm, clip);
2956 return handle;
2957 }
2958 return nullptr;
2959}
2960
2961static bool install(SkBitmap* bm, const SkImageInfo& info,
2962 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002963 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002964}
2965
2966SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2967 SkBitmap* bm) {
2968 SkRasterHandleAllocator::Rec rec;
2969 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2970 return nullptr;
2971 }
2972 return rec.fHandle;
2973}
2974
2975std::unique_ptr<SkCanvas>
2976SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2977 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002978 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002979 return nullptr;
2980 }
2981
2982 SkBitmap bm;
2983 Handle hndl;
2984
2985 if (rec) {
2986 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2987 } else {
2988 hndl = alloc->allocBitmap(info, &bm);
2989 }
2990 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2991}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002992
2993///////////////////////////////////////////////////////////////////////////////////////////////////