blob: b6e9d197313bdbd7661dad988aa1791629f3fa69 [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"
11#include "include/core/SkDrawLooper.h"
12#include "include/core/SkImage.h"
13#include "include/core/SkImageFilter.h"
14#include "include/core/SkPathEffect.h"
15#include "include/core/SkPicture.h"
16#include "include/core/SkRRect.h"
17#include "include/core/SkRasterHandleAllocator.h"
18#include "include/core/SkString.h"
19#include "include/core/SkTextBlob.h"
20#include "include/core/SkVertices.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "include/private/SkNx.h"
22#include "include/private/SkTo.h"
23#include "include/utils/SkNoDrawCanvas.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040024#include "src/core/SkArenaAlloc.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/core/SkBitmapDevice.h"
26#include "src/core/SkCanvasPriv.h"
27#include "src/core/SkClipOpPriv.h"
28#include "src/core/SkClipStack.h"
29#include "src/core/SkDraw.h"
30#include "src/core/SkGlyphRun.h"
31#include "src/core/SkImageFilterCache.h"
Michael Ludwig08b260c2019-05-17 11:21:53 -040032#include "src/core/SkImageFilterPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050033#include "src/core/SkLatticeIter.h"
34#include "src/core/SkMSAN.h"
35#include "src/core/SkMakeUnique.h"
36#include "src/core/SkMatrixUtils.h"
37#include "src/core/SkPaintPriv.h"
38#include "src/core/SkRasterClip.h"
39#include "src/core/SkSpecialImage.h"
40#include "src/core/SkStrikeCache.h"
41#include "src/core/SkTLazy.h"
42#include "src/core/SkTextFormatParams.h"
43#include "src/core/SkTraceEvent.h"
44#include "src/image/SkImage_Base.h"
45#include "src/image/SkSurface_Base.h"
46#include "src/utils/SkPatchUtils.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040047
bungemand3ebb482015-08-05 13:57:49 -070048#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050051#include "include/gpu/GrContext.h"
52#include "src/gpu/SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053#endif
54
reede3b38ce2016-01-08 09:18:44 -080055#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050056#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080057
Mike Reed139e5e02017-03-08 11:29:33 -050058///////////////////////////////////////////////////////////////////////////////////////////////////
59
reedc83a2972015-07-16 07:40:45 -070060/*
61 * Return true if the drawing this rect would hit every pixels in the canvas.
62 *
63 * Returns false if
64 * - rect does not contain the canvas' bounds
65 * - paint is not fill
66 * - paint would blur or otherwise change the coverage of the rect
67 */
68bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
69 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070070 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
71 (int)kNone_ShaderOverrideOpacity,
72 "need_matching_enums0");
73 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
74 (int)kOpaque_ShaderOverrideOpacity,
75 "need_matching_enums1");
76 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
77 (int)kNotOpaque_ShaderOverrideOpacity,
78 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070079
80 const SkISize size = this->getBaseLayerSize();
81 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050082
83 // if we're clipped at all, we can't overwrite the entire surface
84 {
85 SkBaseDevice* base = this->getDevice();
86 SkBaseDevice* top = this->getTopDevice();
87 if (base != top) {
88 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
89 }
90 if (!base->clipIsWideOpen()) {
91 return false;
92 }
reedc83a2972015-07-16 07:40:45 -070093 }
94
95 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070096 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070097 return false; // conservative
98 }
halcanaryc5769b22016-08-10 07:13:21 -070099
100 SkRect devRect;
101 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
102 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700103 return false;
104 }
105 }
106
107 if (paint) {
108 SkPaint::Style paintStyle = paint->getStyle();
109 if (!(paintStyle == SkPaint::kFill_Style ||
110 paintStyle == SkPaint::kStrokeAndFill_Style)) {
111 return false;
112 }
113 if (paint->getMaskFilter() || paint->getLooper()
114 || paint->getPathEffect() || paint->getImageFilter()) {
115 return false; // conservative
116 }
117 }
118 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
119}
120
121///////////////////////////////////////////////////////////////////////////////////////////////////
122
reed@google.comda17f752012-08-16 18:27:05 +0000123// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124//#define SK_TRACE_SAVERESTORE
125
126#ifdef SK_TRACE_SAVERESTORE
127 static int gLayerCounter;
128 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
129 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
130
131 static int gRecCounter;
132 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
133 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
134
135 static int gCanvasCounter;
136 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
137 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
138#else
139 #define inc_layer()
140 #define dec_layer()
141 #define inc_rec()
142 #define dec_rec()
143 #define inc_canvas()
144 #define dec_canvas()
145#endif
146
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000147typedef SkTLazy<SkPaint> SkLazyPaint;
148
reedc83a2972015-07-16 07:40:45 -0700149void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000150 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700151 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
152 ? SkSurface::kDiscard_ContentChangeMode
153 : SkSurface::kRetain_ContentChangeMode);
154 }
155}
156
157void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
158 ShaderOverrideOpacity overrideOpacity) {
159 if (fSurfaceBase) {
160 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
161 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
162 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
163 // and therefore we don't care which mode we're in.
164 //
165 if (fSurfaceBase->outstandingImageSnapshot()) {
166 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
167 mode = SkSurface::kDiscard_ContentChangeMode;
168 }
169 }
170 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000171 }
172}
173
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000176/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 The clip/matrix/proc are fields that reflect the top of the save/restore
178 stack. Whenever the canvas changes, it marks a dirty flag, and then before
179 these are used (assuming we're not on a layer) we rebuild these cache
180 values: they reflect the top of the save stack, but translated and clipped
181 by the device's XY offset and bitmap-bounds.
182*/
183struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400184 DeviceCM* fNext;
185 sk_sp<SkBaseDevice> fDevice;
186 SkRasterClip fClip;
187 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
188 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400189 sk_sp<SkImage> fClipImage;
190 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191
Florin Malita53f77bd2017-04-28 13:48:37 -0400192 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000193 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700194 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400195 , fDevice(std::move(device))
196 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700197 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000198 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400199 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400200 {}
reed@google.com4b226022011-01-11 18:32:13 +0000201
mtkleinfeaadee2015-04-08 11:25:48 -0700202 void reset(const SkIRect& bounds) {
203 SkASSERT(!fPaint);
204 SkASSERT(!fNext);
205 SkASSERT(fDevice);
206 fClip.setRect(bounds);
207 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208};
209
Mike Reed148b7fd2018-12-18 17:38:18 -0500210namespace {
211// Encapsulate state needed to restore from saveBehind()
212struct BackImage {
213 sk_sp<SkSpecialImage> fImage;
214 SkIPoint fLoc;
215};
216}
217
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218/* This is the record we keep for each save/restore level in the stack.
219 Since a level optionally copies the matrix and/or stack, we have pointers
220 for these fields. If the value is copied for this level, the copy is
221 stored in the ...Storage field, and the pointer points to that. If the
222 value is not copied for this level, we ignore ...Storage, and just point
223 at the corresponding value in the previous level in the stack.
224*/
225class SkCanvas::MCRec {
226public:
Mike Reed148b7fd2018-12-18 17:38:18 -0500227 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 /* If there are any layers in the stack, this points to the top-most
229 one that is at or below this level in the stack (so we know what
230 bitmap/device to draw into from this level. This value is NOT
231 reference counted, since the real owner is either our fLayer field,
232 or a previous one in a lower level.)
233 */
Mike Reed148b7fd2018-12-18 17:38:18 -0500234 DeviceCM* fTopLayer;
235 std::unique_ptr<BackImage> fBackImage;
236 SkConservativeClip fRasterClip;
237 SkMatrix fMatrix;
238 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239
Mike Reeda1361362017-03-07 09:37:29 -0500240 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700241 fLayer = nullptr;
242 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800243 fMatrix.reset();
244 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700245
reedd9544982014-09-09 18:46:22 -0700246 // don't bother initializing fNext
247 inc_rec();
248 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400249 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700250 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700251 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800252 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700253
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 // don't bother initializing fNext
255 inc_rec();
256 }
257 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700258 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259 dec_rec();
260 }
mtkleinfeaadee2015-04-08 11:25:48 -0700261
262 void reset(const SkIRect& bounds) {
263 SkASSERT(fLayer);
264 SkASSERT(fDeferredSaveCount == 0);
265
266 fMatrix.reset();
267 fRasterClip.setRect(bounds);
268 fLayer->reset(bounds);
269 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270};
271
Mike Reeda1361362017-03-07 09:37:29 -0500272class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273public:
Mike Reeda1361362017-03-07 09:37:29 -0500274 SkDrawIter(SkCanvas* canvas)
275 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
276 {}
reed@google.com4b226022011-01-11 18:32:13 +0000277
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000279 const DeviceCM* rec = fCurrLayer;
280 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400281 fDevice = rec->fDevice.get();
282 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700284 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 return true;
286 }
287 return false;
288 }
reed@google.com4b226022011-01-11 18:32:13 +0000289
reed@google.com6f8f2922011-03-04 22:27:10 +0000290 int getX() const { return fDevice->getOrigin().x(); }
291 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000293
Mike Reed99330ba2017-02-22 11:01:08 -0500294 SkBaseDevice* fDevice;
295
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 const DeviceCM* fCurrLayer;
298 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299};
300
Florin Malita713b8ef2017-04-28 10:57:24 -0400301#define FOR_EACH_TOP_DEVICE( code ) \
302 do { \
303 DeviceCM* layer = fMCRec->fTopLayer; \
304 while (layer) { \
305 SkBaseDevice* device = layer->fDevice.get(); \
306 if (device) { \
307 code; \
308 } \
309 layer = layer->fNext; \
310 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500311 } while (0)
312
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313/////////////////////////////////////////////////////////////////////////////
314
reeddbc3cef2015-04-29 12:18:57 -0700315static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
316 return lazy->isValid() ? lazy->get() : lazy->set(orig);
317}
318
319/**
320 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700321 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700322 */
reedd053ce92016-03-22 10:17:23 -0700323static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700324 SkImageFilter* imgf = paint.getImageFilter();
325 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700326 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700327 }
328
reedd053ce92016-03-22 10:17:23 -0700329 SkColorFilter* imgCFPtr;
330 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700331 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700332 }
reedd053ce92016-03-22 10:17:23 -0700333 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700334
335 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700336 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700337 // there is no existing paint colorfilter, so we can just return the imagefilter's
338 return imgCF;
339 }
340
341 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
342 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500343 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700344}
345
senorblanco87e066e2015-10-28 11:23:36 -0700346/**
347 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
348 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
349 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
350 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
351 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
352 * conservative "effective" bounds based on the settings in the paint... with one exception. This
353 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
354 * deliberately ignored.
355 */
356static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
357 const SkRect& rawBounds,
358 SkRect* storage) {
359 SkPaint tmpUnfiltered(paint);
360 tmpUnfiltered.setImageFilter(nullptr);
361 if (tmpUnfiltered.canComputeFastBounds()) {
362 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
363 } else {
364 return rawBounds;
365 }
366}
367
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368class AutoDrawLooper {
369public:
senorblanco87e066e2015-10-28 11:23:36 -0700370 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
371 // paint. It's used to determine the size of the offscreen layer for filters.
372 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700373 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700374 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000375 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700376 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000377 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700378 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000379 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380
reedd053ce92016-03-22 10:17:23 -0700381 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700382 if (simplifiedCF) {
383 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700384 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700385 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700386 fPaint = paint;
387 }
388
389 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700390 /**
391 * We implement ImageFilters for a given draw by creating a layer, then applying the
392 * imagefilter to the pixels of that layer (its backing surface/image), and then
393 * we call restore() to xfer that layer to the main canvas.
394 *
395 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
396 * 2. Generate the src pixels:
397 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
398 * return (fPaint). We then draw the primitive (using srcover) into a cleared
399 * buffer/surface.
400 * 3. Restore the layer created in #1
401 * The imagefilter is passed the buffer/surface from the layer (now filled with the
402 * src pixels of the primitive). It returns a new "filtered" buffer, which we
403 * draw onto the previous layer using the xfermode from the original paint.
404 */
reed@google.com8926b162012-03-23 15:36:36 +0000405 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500406 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700407 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700408 SkRect storage;
409 if (rawBounds) {
410 // Make rawBounds include all paint outsets except for those due to image filters.
411 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
412 }
reedbfd5f172016-01-07 11:28:08 -0800413 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700414 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700415 fTempLayerForImageFilter = true;
416 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000417 }
418
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000419 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500420 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000421 fIsSimple = false;
422 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700423 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000424 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400425 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000426 }
427 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000428
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700430 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000431 fCanvas->internalRestore();
432 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000433 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000435
reed@google.com4e2b3d32011-04-07 14:18:59 +0000436 const SkPaint& paint() const {
437 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400438 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000439 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000441
Ben Wagner2c312c42018-06-27 14:46:46 -0400442 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000443 if (fDone) {
444 return false;
445 } else if (fIsSimple) {
446 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000447 return !fPaint->nothingToDraw();
448 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400449 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000450 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000451 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000452
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500454 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700455 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000456 SkCanvas* fCanvas;
457 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000458 const SkPaint* fPaint;
459 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700460 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000461 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000462 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000463 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400464 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000465
Ben Wagner2c312c42018-06-27 14:46:46 -0400466 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000467};
468
Ben Wagner2c312c42018-06-27 14:46:46 -0400469bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700470 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000471 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400472 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000473
reeddbc3cef2015-04-29 12:18:57 -0700474 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
475 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400476 // never want our downstream clients (i.e. devices) to see loopers
477 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000478
reed5c476fb2015-04-20 08:04:21 -0700479 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700480 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700481 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000483
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000484 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000485 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000486 return false;
487 }
reed@google.com129ec222012-05-15 13:24:09 +0000488 fPaint = paint;
489
490 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400491 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000492 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000493 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000494 return true;
495}
496
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497////////// macros to place around the internal draw calls //////////////////
498
reed3aafe112016-08-18 12:45:34 -0700499#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
500 this->predrawNotify(); \
501 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400502 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800503 SkDrawIter iter(this);
504
505
Ben Wagner2c312c42018-06-27 14:46:46 -0400506#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000507 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700508 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400509 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000510 SkDrawIter iter(this);
511
Ben Wagner2c312c42018-06-27 14:46:46 -0400512#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000513 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700514 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400515 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000517
Ben Wagner2c312c42018-06-27 14:46:46 -0400518#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700519 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700520 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400521 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700522 SkDrawIter iter(this);
523
reed@google.com4e2b3d32011-04-07 14:18:59 +0000524#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525
526////////////////////////////////////////////////////////////////////////////
527
msarettfbfa2582016-08-12 08:29:08 -0700528static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
529 if (bounds.isEmpty()) {
530 return SkRect::MakeEmpty();
531 }
532
533 // Expand bounds out by 1 in case we are anti-aliasing. We store the
534 // bounds as floats to enable a faster quick reject implementation.
535 SkRect dst;
536 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
537 return dst;
538}
539
mtkleinfeaadee2015-04-08 11:25:48 -0700540void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
541 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700542 fMCRec->reset(bounds);
543
544 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500545 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400546 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700547 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700548 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700549}
550
Hal Canary363a3f82018-10-04 11:04:48 -0400551void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000552 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800553 fSaveCount = 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554
555 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500556 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500557 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700558 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559
reeda499f902015-05-01 09:34:31 -0700560 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
561 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400562 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700563
reed@android.com8a1c16f2008-12-17 15:59:43 +0000564 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000565
halcanary96fcdcc2015-08-27 07:41:13 -0700566 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000567
reedf92c8662014-08-18 08:02:43 -0700568 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700569 // The root device and the canvas should always have the same pixel geometry
570 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800571 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700572 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500573
Mike Reedc42a1cd2017-02-14 14:25:14 -0500574 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700575 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400576
Herb Derby59d997a2018-06-07 12:44:09 -0400577 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578}
579
reed@google.comcde92112011-07-06 20:00:52 +0000580SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000581 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700582 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000583{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000584 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000585
Hal Canary363a3f82018-10-04 11:04:48 -0400586 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000587}
588
reed96a857e2015-01-25 10:33:58 -0800589SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000590 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800591 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000592{
593 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400594 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400595 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700596}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000597
Hal Canary363a3f82018-10-04 11:04:48 -0400598SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700599 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700600 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700601{
602 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700603
Mike Reed566e53c2017-03-10 10:49:45 -0500604 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400605 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700606}
607
Herb Derbyefe39bc2018-05-01 17:06:20 -0400608SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000609 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700610 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000611{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700613
Hal Canary363a3f82018-10-04 11:04:48 -0400614 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700615}
616
reed4a8126e2014-09-22 07:29:03 -0700617SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700618 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700619 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700620{
621 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700622
Mike Reed910ca0f2018-04-25 13:04:05 -0400623 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400624 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700625}
reed29c857d2014-09-21 10:25:07 -0700626
Mike Reed356f7c22017-01-10 11:58:39 -0500627SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
628 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700629 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
630 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500631 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700632{
633 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700634
Mike Reed910ca0f2018-04-25 13:04:05 -0400635 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400636 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637}
638
Mike Reed356f7c22017-01-10 11:58:39 -0500639SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
640
Matt Sarett31f99ce2017-04-11 08:46:01 -0400641#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
642SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
643 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
644 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
645 , fAllocator(nullptr)
646{
647 inc_canvas();
648
649 SkBitmap tmp(bitmap);
650 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400651 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400652 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400653}
654#endif
655
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656SkCanvas::~SkCanvas() {
657 // free up the contents of our deque
658 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000659
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660 this->internalRestore(); // restore the last, since we're going away
661
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 dec_canvas();
663}
664
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665///////////////////////////////////////////////////////////////////////////////
666
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000667void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700668 this->onFlush();
669}
670
671void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000672 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000673 if (device) {
674 device->flush();
675 }
676}
677
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000678SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000679 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000680 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
681}
682
senorblancoafc7cce2016-02-02 18:44:15 -0800683SkIRect SkCanvas::getTopLayerBounds() const {
684 SkBaseDevice* d = this->getTopDevice();
685 if (!d) {
686 return SkIRect::MakeEmpty();
687 }
688 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
689}
690
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000691SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000693 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000694 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400695 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696}
697
Florin Malita0ed3b642017-01-13 16:56:38 +0000698SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400699 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000700}
701
Mike Reed353196f2017-07-21 11:01:18 -0400702bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000703 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400704 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000705}
706
Mike Reed353196f2017-07-21 11:01:18 -0400707bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
708 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400709}
710
711bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
712 SkPixmap pm;
713 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
714}
715
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000716bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400717 SkPixmap pm;
718 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700719 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000720 }
721 return false;
722}
723
Matt Sarett03dd6d52017-01-23 12:15:09 -0500724bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000725 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000726 SkBaseDevice* device = this->getDevice();
727 if (!device) {
728 return false;
729 }
730
Matt Sarett03dd6d52017-01-23 12:15:09 -0500731 // This check gives us an early out and prevents generation ID churn on the surface.
732 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
733 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
734 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
735 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000736 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000737
Matt Sarett03dd6d52017-01-23 12:15:09 -0500738 // Tell our owning surface to bump its generation ID.
739 const bool completeOverwrite =
740 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700741 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700742
Matt Sarett03dd6d52017-01-23 12:15:09 -0500743 // This can still fail, most notably in the case of a invalid color type or alpha type
744 // conversion. We could pull those checks into this function and avoid the unnecessary
745 // generation ID bump. But then we would be performing those checks twice, since they
746 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400747 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000748}
reed@google.com51df9e32010-12-23 19:29:18 +0000749
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750//////////////////////////////////////////////////////////////////////////////
751
reed2ff1fce2014-12-11 07:07:37 -0800752void SkCanvas::checkForDeferredSave() {
753 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800754 this->doSave();
755 }
756}
757
reedf0090cb2014-11-26 08:55:51 -0800758int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800759#ifdef SK_DEBUG
760 int count = 0;
761 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
762 for (;;) {
763 const MCRec* rec = (const MCRec*)iter.next();
764 if (!rec) {
765 break;
766 }
767 count += 1 + rec->fDeferredSaveCount;
768 }
769 SkASSERT(count == fSaveCount);
770#endif
771 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800772}
773
774int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800775 fSaveCount += 1;
776 fMCRec->fDeferredSaveCount += 1;
777 return this->getSaveCount() - 1; // return our prev value
778}
779
780void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800781 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700782
783 SkASSERT(fMCRec->fDeferredSaveCount > 0);
784 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800785 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800786}
787
788void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800789 if (fMCRec->fDeferredSaveCount > 0) {
790 SkASSERT(fSaveCount > 1);
791 fSaveCount -= 1;
792 fMCRec->fDeferredSaveCount -= 1;
793 } else {
794 // check for underflow
795 if (fMCStack.count() > 1) {
796 this->willRestore();
797 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700798 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800799 this->internalRestore();
800 this->didRestore();
801 }
reedf0090cb2014-11-26 08:55:51 -0800802 }
803}
804
805void SkCanvas::restoreToCount(int count) {
806 // sanity check
807 if (count < 1) {
808 count = 1;
809 }
mtkleinf0f14112014-12-12 08:46:25 -0800810
reedf0090cb2014-11-26 08:55:51 -0800811 int n = this->getSaveCount() - count;
812 for (int i = 0; i < n; ++i) {
813 this->restore();
814 }
815}
816
reed2ff1fce2014-12-11 07:07:37 -0800817void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700819 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000821
Mike Reedc42a1cd2017-02-14 14:25:14 -0500822 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823}
824
reed4960eee2015-12-18 07:09:18 -0800825bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400826 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827}
828
reed4960eee2015-12-18 07:09:18 -0800829bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700830 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500831 SkIRect clipBounds = this->getDeviceClipBounds();
832 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000833 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000834 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000835
reed96e657d2015-03-10 17:30:07 -0700836 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
837
Robert Phillips12078432018-05-17 11:17:39 -0400838 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
839 // If the image filter DAG affects transparent black then we will need to render
840 // out to the clip bounds
841 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000842 }
Robert Phillips12078432018-05-17 11:17:39 -0400843
844 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700845 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000846 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700847 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400848 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000849 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400850 inputSaveLayerBounds = clipBounds;
851 }
852
853 if (imageFilter) {
854 // expand the clip bounds by the image filter DAG to include extra content that might
855 // be required by the image filters.
856 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
857 SkImageFilter::kReverse_MapDirection,
858 &inputSaveLayerBounds);
859 }
860
861 SkIRect clippedSaveLayerBounds;
862 if (bounds) {
863 // For better or for worse, user bounds currently act as a hard clip on the layer's
864 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
865 clippedSaveLayerBounds = inputSaveLayerBounds;
866 } else {
867 // If there are no user bounds, we don't want to artificially restrict the resulting
868 // layer bounds, so allow the expanded clip bounds free reign.
869 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800871
872 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400873 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800874 if (BoundsAffectsClip(saveLayerFlags)) {
875 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
876 fMCRec->fRasterClip.setEmpty();
877 fDeviceClipBounds.setEmpty();
878 }
879 return false;
880 }
Robert Phillips12078432018-05-17 11:17:39 -0400881 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000882
reed4960eee2015-12-18 07:09:18 -0800883 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700884 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400885 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
886 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000887 }
888
889 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400890 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000891 }
Robert Phillips12078432018-05-17 11:17:39 -0400892
junov@chromium.orga907ac32012-02-24 21:54:07 +0000893 return true;
894}
895
reed4960eee2015-12-18 07:09:18 -0800896int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
897 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000898}
899
Cary Clarke041e312018-03-06 13:00:52 -0500900int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700901 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400902 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
903 // no need for the layer (or any of the draws until the matching restore()
904 this->save();
905 this->clipRect({0,0,0,0});
906 } else {
907 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
908 fSaveCount += 1;
909 this->internalSaveLayer(rec, strategy);
910 }
reed4960eee2015-12-18 07:09:18 -0800911 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800912}
913
Mike Reed148b7fd2018-12-18 17:38:18 -0500914int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
915 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
916 // Assuming clips never expand, if the request bounds is outside of the current clip
917 // there is no need to copy/restore the area, so just devolve back to a regular save.
918 this->save();
919 } else {
920 bool doTheWork = this->onDoSaveBehind(bounds);
921 fSaveCount += 1;
922 this->internalSave();
923 if (doTheWork) {
924 this->internalSaveBehind(bounds);
925 }
926 }
927 return this->getSaveCount() - 1;
928}
929
reeda2217ef2016-07-20 06:04:34 -0700930void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500931 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500932 const SkMatrix& ctm) {
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400933 SkPaint p;
Michael Ludwig08b260c2019-05-17 11:21:53 -0400934 SkIRect snapBounds = SkIRect::MakeXYWH(dstOrigin.x() - src->getOrigin().x(),
935 dstOrigin.y() - src->getOrigin().y(),
936 dst->width(), dst->height());
937 int x = 0;
938 int y = 0;
939
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400940 if (filter) {
Michael Ludwig08b260c2019-05-17 11:21:53 -0400941 // Calculate expanded snap bounds
942 SkIRect newBounds = filter->filterBounds(
943 snapBounds, ctm, SkImageFilter::kReverse_MapDirection, &snapBounds);
944 // Must clamp to valid src since the filter or rotations may expand beyond what's readable
945 SkIRect srcR = SkIRect::MakeWH(src->width(), src->height());
946 if (!newBounds.intersect(srcR)) {
947 return;
948 }
949
950 x = newBounds.fLeft - snapBounds.fLeft;
951 y = newBounds.fTop - snapBounds.fTop;
952 snapBounds = newBounds;
953
954 SkMatrix localCTM;
955 sk_sp<SkImageFilter> modifiedFilter = SkApplyCTMToBackdropFilter(filter, ctm, &localCTM);
956 // Account for the origin offset in the CTM
957 localCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
958
959 // In this case we always wrap the filter (even when it's the original) with 'localCTM'
960 // since there's no device CTM stack that provides it to the image filter context.
961 // FIXME skbug.com/9074 - once perspective is properly supported, drop the
962 // localCTM.hasPerspective condition from assert.
963 SkASSERT(localCTM.isScaleTranslate() || filter->canHandleComplexCTM() ||
964 localCTM.hasPerspective());
965 p.setImageFilter(modifiedFilter->makeWithLocalMatrix(localCTM));
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400966 }
967
Michael Ludwig08b260c2019-05-17 11:21:53 -0400968 auto special = src->snapBackImage(snapBounds);
reeda2217ef2016-07-20 06:04:34 -0700969 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400970 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700971 }
robertphillips7354a4b2015-12-16 05:08:27 -0800972}
reed70ee31b2015-12-10 13:44:45 -0800973
Mike Reed25394292019-03-07 09:36:36 -0500974// This is shared by all backends, but contains raster-specific thoughts. Can we defer to the
975// device to perform this?
Mike Kleine083f7c2018-02-07 12:54:27 -0500976static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500977 // Need to force L32 for now if we have an image filter.
Mike Reed25394292019-03-07 09:36:36 -0500978 // If filters ever support other colortypes, e.g. F16, we can modify this check.
Mike Klein649fb732018-02-26 15:09:16 -0500979 if (paint && paint->getImageFilter()) {
Mike Reed25394292019-03-07 09:36:36 -0500980 // TODO: can we query the imagefilter, to see if it can handle floats (so we don't always
981 // use N32 when the layer itself was float)?
982 return SkImageInfo::MakeN32Premul(w, h, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800983 }
Mike Klein649fb732018-02-26 15:09:16 -0500984
985 SkColorType ct = prev.colorType();
986 if (prev.bytesPerPixel() <= 4) {
987 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
988 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
989 ct = kN32_SkColorType;
990 }
991 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800992}
993
reed4960eee2015-12-18 07:09:18 -0800994void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700995 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800996 const SkRect* bounds = rec.fBounds;
997 const SkPaint* paint = rec.fPaint;
998 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
999
Mike Reed5532c2a2019-02-23 12:00:32 -05001000 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
1001 // regardless of any hint-rect from the caller. skbug.com/8783
1002 if (rec.fBackdrop) {
1003 bounds = nullptr;
1004 }
1005
reed8c30a812016-04-20 16:36:51 -07001006 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001007 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001008 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -04001009 MCRec* modifiedRec = nullptr;
Michael Ludwig08b260c2019-05-17 11:21:53 -04001010
reed8c30a812016-04-20 16:36:51 -07001011 /*
Michael Ludwig08b260c2019-05-17 11:21:53 -04001012 * Many ImageFilters (so far) do not (on their own) correctly handle matrices (CTM) that
1013 * contain rotation/skew/etc. We rely on applyCTM to create a new image filter DAG as needed to
1014 * accommodate this, but it requires update the CTM we use when drawing into the layer.
reed8c30a812016-04-20 16:36:51 -07001015 *
1016 * 1. Stash off the current CTM
Michael Ludwig08b260c2019-05-17 11:21:53 -04001017 * 2. Apply the CTM to imagefilter, which decomposes it into simple and complex transforms
1018 * if necessary.
1019 * 3. Wack the CTM to be the remaining scale matrix and use the modified imagefilter, which
1020 * is a MatrixImageFilter that contains the complex matrix.
reed8c30a812016-04-20 16:36:51 -07001021 * 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 -04001022 * 5. During restore, the MatrixImageFilter automatically applies complex stage to the output
reed8c30a812016-04-20 16:36:51 -07001023 * of the original imagefilter, and draw that (via drawSprite)
1024 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1025 *
1026 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1027 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1028 */
Michael Ludwig08b260c2019-05-17 11:21:53 -04001029 if (imageFilter) {
1030 SkMatrix modifiedCTM;
1031 sk_sp<SkImageFilter> modifiedFilter = SkApplyCTMToFilter(imageFilter, stashedMatrix,
1032 &modifiedCTM);
1033 if (!SkIsSameFilter(modifiedFilter.get(), imageFilter)) {
1034 // The original filter couldn't support the CTM entirely
1035 SkASSERT(modifiedCTM.isScaleTranslate() || imageFilter->canHandleComplexCTM());
1036 modifiedRec = fMCRec;
1037 this->internalSetMatrix(modifiedCTM);
1038 SkPaint* p = lazyP.set(*paint);
1039 p->setImageFilter(std::move(modifiedFilter));
1040 imageFilter = p->getImageFilter();
1041 paint = p;
1042 }
1043 // Else the filter didn't change, so modifiedCTM == stashedMatrix and there's nothing
1044 // left to do since the stack already has that as the CTM.
reed8c30a812016-04-20 16:36:51 -07001045 }
reed8c30a812016-04-20 16:36:51 -07001046
junov@chromium.orga907ac32012-02-24 21:54:07 +00001047 // do this before we create the layer. We don't call the public save() since
1048 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001049 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001050
junov@chromium.orga907ac32012-02-24 21:54:07 +00001051 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001052 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001053 if (modifiedRec) {
1054 // In this case there will be no layer in which to stash the matrix so we need to
1055 // revert the prior MCRec to its earlier state.
1056 modifiedRec->fMatrix = stashedMatrix;
1057 }
reed2ff1fce2014-12-11 07:07:37 -08001058 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059 }
1060
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001061 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1062 // the clipRectBounds() call above?
1063 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001064 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001065 }
1066
reed8dc0ccb2015-03-20 06:32:52 -07001067 SkPixelGeometry geo = fProps.pixelGeometry();
1068 if (paint) {
reed76033be2015-03-14 10:54:31 -07001069 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001070 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001071 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001072 }
1073 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001074
robertphillips5139e502016-07-19 05:10:40 -07001075 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001076 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001077 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001078 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001079 }
reedb2db8982014-11-13 12:41:02 -08001080
Mike Kleine083f7c2018-02-07 12:54:27 -05001081 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
Mike Reed1f3548c2019-07-12 12:53:11 -04001082 if (rec.fSaveLayerFlags & kF16ColorType) {
1083 info = info.makeColorType(kRGBA_F16_SkColorType);
1084 }
reed129ed1c2016-02-22 06:42:31 -08001085
Hal Canary704cd322016-11-07 14:13:52 -05001086 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001087 {
Florin Malita07e4adf2019-01-07 16:34:18 -05001088 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType();
reeddaa57bf2015-05-15 10:39:17 -07001089 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001090 const bool trackCoverage =
1091 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001092 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001093 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001094 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001095 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001096 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1097 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001098 return;
reed61f501f2015-04-29 08:34:00 -07001099 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001100 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001101 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001102
Mike Reedb43a3e02017-02-11 10:18:58 -05001103 // only have a "next" if this new layer doesn't affect the clip (rare)
1104 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001105 fMCRec->fLayer = layer;
1106 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001107
Mike Reedc61abee2017-02-28 17:45:27 -05001108 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001109 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001110 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001111 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001112
Mike Reedc42a1cd2017-02-14 14:25:14 -05001113 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1114
1115 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1116 if (layer->fNext) {
1117 // need to punch a hole in the previous device, so we don't draw there, given that
1118 // the new top-layer will allow drawing to happen "below" it.
1119 SkRegion hole(ir);
1120 do {
1121 layer = layer->fNext;
1122 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1123 } while (layer->fNext);
1124 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001125}
1126
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001127int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001128 if (0xFF == alpha) {
1129 return this->saveLayer(bounds, nullptr);
1130 } else {
1131 SkPaint tmpPaint;
1132 tmpPaint.setAlpha(alpha);
1133 return this->saveLayer(bounds, &tmpPaint);
1134 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001135}
1136
Mike Reed148b7fd2018-12-18 17:38:18 -05001137void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1138 SkIRect devBounds;
1139 if (localBounds) {
1140 SkRect tmp;
1141 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1142 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1143 devBounds.setEmpty();
1144 }
1145 } else {
1146 devBounds = this->getDeviceClipBounds();
1147 }
1148 if (devBounds.isEmpty()) {
1149 return;
1150 }
1151
1152 SkBaseDevice* device = this->getTopDevice();
1153 if (nullptr == device) { // Do we still need this check???
1154 return;
1155 }
1156
1157 // need the bounds relative to the device itself
1158 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1159
1160 auto backImage = device->snapBackImage(devBounds);
1161 if (!backImage) {
1162 return;
1163 }
1164
1165 // we really need the save, so we can wack the fMCRec
1166 this->checkForDeferredSave();
1167
1168 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1169
1170 SkPaint paint;
1171 paint.setBlendMode(SkBlendMode::kClear);
Mike Reed9adc82c2019-04-23 10:28:13 -04001172 this->drawClippedToSaveBehind(paint);
Mike Reed148b7fd2018-12-18 17:38:18 -05001173}
1174
reed@android.com8a1c16f2008-12-17 15:59:43 +00001175void SkCanvas::internalRestore() {
1176 SkASSERT(fMCStack.count() != 0);
1177
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001178 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001179 DeviceCM* layer = fMCRec->fLayer; // may be null
1180 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001181 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182
Mike Reed148b7fd2018-12-18 17:38:18 -05001183 // move this out before we do the actual restore
1184 auto backImage = std::move(fMCRec->fBackImage);
1185
reed@android.com8a1c16f2008-12-17 15:59:43 +00001186 // now do the normal restore()
1187 fMCRec->~MCRec(); // balanced in save()
1188 fMCStack.pop_back();
1189 fMCRec = (MCRec*)fMCStack.back();
1190
Mike Reedc42a1cd2017-02-14 14:25:14 -05001191 if (fMCRec) {
1192 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1193 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001194
Mike Reed148b7fd2018-12-18 17:38:18 -05001195 if (backImage) {
1196 SkPaint paint;
1197 paint.setBlendMode(SkBlendMode::kDstOver);
1198 const int x = backImage->fLoc.x();
1199 const int y = backImage->fLoc.y();
1200 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1201 nullptr, SkMatrix::I());
1202 }
1203
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1205 since if we're being recorded, we don't want to record this (the
1206 recorder will have already recorded the restore).
1207 */
bsalomon49f085d2014-09-05 13:34:00 -07001208 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001209 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001210 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001211 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001212 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001213 layer->fPaint.get(),
1214 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001215 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001216 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001217 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001218 delete layer;
reedb679ca82015-04-07 04:40:48 -07001219 } else {
1220 // we're at the root
reeda499f902015-05-01 09:34:31 -07001221 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001222 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001223 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001225 }
msarettfbfa2582016-08-12 08:29:08 -07001226
1227 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001228 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001229 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1230 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001231}
1232
reede8f30622016-03-23 18:59:25 -07001233sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001234 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001235 props = &fProps;
1236 }
1237 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001238}
1239
reede8f30622016-03-23 18:59:25 -07001240sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001241 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001242 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001243}
1244
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001245SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001246 return this->onImageInfo();
1247}
1248
1249SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001250 SkBaseDevice* dev = this->getDevice();
1251 if (dev) {
1252 return dev->imageInfo();
1253 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001254 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001255 }
1256}
1257
brianosman898235c2016-04-06 07:38:23 -07001258bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001259 return this->onGetProps(props);
1260}
1261
1262bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001263 SkBaseDevice* dev = this->getDevice();
1264 if (dev) {
1265 if (props) {
1266 *props = fProps;
1267 }
1268 return true;
1269 } else {
1270 return false;
1271 }
1272}
1273
reed6ceeebd2016-03-09 14:26:26 -08001274bool SkCanvas::peekPixels(SkPixmap* pmap) {
1275 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001276}
1277
reed884e97c2015-05-26 11:31:54 -07001278bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001279 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001280 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001281}
1282
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001283void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001284 SkPixmap pmap;
1285 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001286 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001287 }
1288 if (info) {
1289 *info = pmap.info();
1290 }
1291 if (rowBytes) {
1292 *rowBytes = pmap.rowBytes();
1293 }
1294 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001295 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001296 }
reed884e97c2015-05-26 11:31:54 -07001297 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001298}
1299
reed884e97c2015-05-26 11:31:54 -07001300bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001301 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001302 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001303}
1304
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306
Mike Reed8bcd1282019-03-13 16:51:54 -04001307// In our current design/features, we should never have a layer (src) in a different colorspace
1308// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1309// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1310// colorspace.
1311static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1312 SkASSERT(src == dst);
1313}
1314
Florin Malita53f77bd2017-04-28 13:48:37 -04001315void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1316 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001318 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 paint = &tmp;
1320 }
reed@google.com4b226022011-01-11 18:32:13 +00001321
Ben Wagner2c312c42018-06-27 14:46:46 -04001322 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001323
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001325 SkBaseDevice* dstDev = iter.fDevice;
Mike Reed8bcd1282019-03-13 16:51:54 -04001326 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1327 srcDev->imageInfo().colorSpace());
reed@google.com76dd2772012-01-05 21:15:07 +00001328 paint = &looper.paint();
1329 SkImageFilter* filter = paint->getImageFilter();
1330 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001331 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001332 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1333 if (specialImage) {
Mike Reed8bcd1282019-03-13 16:51:54 -04001334 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1335 specialImage->getColorSpace());
Florin Malita53f77bd2017-04-28 13:48:37 -04001336 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1337 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001338 }
reed@google.com76dd2772012-01-05 21:15:07 +00001339 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001340 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001341 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342 }
reeda2217ef2016-07-20 06:04:34 -07001343
reed@google.com4e2b3d32011-04-07 14:18:59 +00001344 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001345}
1346
reed32704672015-12-16 08:27:10 -08001347/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001348
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001349void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001350 if (dx || dy) {
1351 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001352 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001353
reedfe69b502016-09-12 06:31:48 -07001354 // Translate shouldn't affect the is-scale-translateness of the matrix.
1355 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001356
Mike Reedc42a1cd2017-02-14 14:25:14 -05001357 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001358
reedfe69b502016-09-12 06:31:48 -07001359 this->didTranslate(dx,dy);
1360 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001361}
1362
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001363void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001364 SkMatrix m;
1365 m.setScale(sx, sy);
1366 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001367}
1368
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001369void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001370 SkMatrix m;
1371 m.setRotate(degrees);
1372 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001373}
1374
bungeman7438bfc2016-07-12 15:01:19 -07001375void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1376 SkMatrix m;
1377 m.setRotate(degrees, px, py);
1378 this->concat(m);
1379}
1380
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001381void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001382 SkMatrix m;
1383 m.setSkew(sx, sy);
1384 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001385}
1386
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001387void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001388 if (matrix.isIdentity()) {
1389 return;
1390 }
1391
reed2ff1fce2014-12-11 07:07:37 -08001392 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001393 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001394 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001395
Mike Reed7627fa52017-02-08 10:07:53 -05001396 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001397
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001398 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001399}
1400
reed8c30a812016-04-20 16:36:51 -07001401void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001402 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001403 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001404
Mike Reedc42a1cd2017-02-14 14:25:14 -05001405 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001406}
1407
1408void SkCanvas::setMatrix(const SkMatrix& matrix) {
1409 this->checkForDeferredSave();
1410 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001411 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412}
1413
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001415 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416}
1417
1418//////////////////////////////////////////////////////////////////////////////
1419
Mike Reedc1f77742016-12-09 09:00:50 -05001420void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001421 if (!rect.isFinite()) {
1422 return;
1423 }
reed2ff1fce2014-12-11 07:07:37 -08001424 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001425 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1426 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001427}
1428
Mike Reedc1f77742016-12-09 09:00:50 -05001429void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001430 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001431
Mike Reed7627fa52017-02-08 10:07:53 -05001432 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001433
reedc64eff52015-11-21 12:39:45 -08001434 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001435 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1436 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001437 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438}
1439
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001440void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1441 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001442 if (fClipRestrictionRect.isEmpty()) {
1443 // we notify the device, but we *dont* resolve deferred saves (since we're just
1444 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001445 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001446 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001447 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001448 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001449 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001450 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001451 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1452 }
1453}
1454
Mike Reedc1f77742016-12-09 09:00:50 -05001455void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001456 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001457 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001458 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001459 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1460 } else {
1461 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001462 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001463}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001464
Mike Reedc1f77742016-12-09 09:00:50 -05001465void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001466 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001467
Brian Salomona3b45d42016-10-03 11:36:16 -04001468 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001469
Mike Reed7627fa52017-02-08 10:07:53 -05001470 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001471
Mike Reed20800c82017-11-15 16:09:04 -05001472 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1473 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001474 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001475}
1476
Mike Reedc1f77742016-12-09 09:00:50 -05001477void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001478 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001479 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001480
1481 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1482 SkRect r;
1483 if (path.isRect(&r)) {
1484 this->onClipRect(r, op, edgeStyle);
1485 return;
1486 }
1487 SkRRect rrect;
1488 if (path.isOval(&r)) {
1489 rrect.setOval(r);
1490 this->onClipRRect(rrect, op, edgeStyle);
1491 return;
1492 }
1493 if (path.isRRect(&rrect)) {
1494 this->onClipRRect(rrect, op, edgeStyle);
1495 return;
1496 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001497 }
robertphillips39f05382015-11-24 09:30:12 -08001498
1499 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001500}
1501
Mike Reedc1f77742016-12-09 09:00:50 -05001502void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001503 AutoValidateClip avc(this);
1504
Brian Salomona3b45d42016-10-03 11:36:16 -04001505 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001506
Mike Reed7627fa52017-02-08 10:07:53 -05001507 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508
Brian Salomona3b45d42016-10-03 11:36:16 -04001509 const SkPath* rasterClipPath = &path;
1510 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001511 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1512 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001513 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001514}
1515
Mike Reedc1f77742016-12-09 09:00:50 -05001516void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001517 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001518 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001519}
1520
Mike Reedc1f77742016-12-09 09:00:50 -05001521void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001522 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001523
reed@google.com5c3d1472011-02-22 19:12:23 +00001524 AutoValidateClip avc(this);
1525
Mike Reed20800c82017-11-15 16:09:04 -05001526 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001527 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001528}
1529
reed@google.com819c9212011-02-23 18:56:55 +00001530#ifdef SK_DEBUG
1531void SkCanvas::validateClip() const {
1532 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001533 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001534 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001535 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001536 return;
1537 }
reed@google.com819c9212011-02-23 18:56:55 +00001538}
1539#endif
1540
Mike Reeda1361362017-03-07 09:37:29 -05001541bool SkCanvas::androidFramework_isClipAA() const {
1542 bool containsAA = false;
1543
1544 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1545
1546 return containsAA;
1547}
1548
1549class RgnAccumulator {
1550 SkRegion* fRgn;
1551public:
1552 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1553 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1554 SkIPoint origin = device->getOrigin();
1555 if (origin.x() | origin.y()) {
1556 rgn->translate(origin.x(), origin.y());
1557 }
1558 fRgn->op(*rgn, SkRegion::kUnion_Op);
1559 }
1560};
1561
1562void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1563 RgnAccumulator accum(rgn);
1564 SkRegion tmp;
1565
1566 rgn->setEmpty();
1567 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001568}
1569
reed@google.com5c3d1472011-02-22 19:12:23 +00001570///////////////////////////////////////////////////////////////////////////////
1571
reed@google.com754de5f2014-02-24 19:38:20 +00001572bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001573 return fMCRec->fRasterClip.isEmpty();
1574
1575 // TODO: should we only use the conservative answer in a recording canvas?
1576#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001577 SkBaseDevice* dev = this->getTopDevice();
1578 // if no device we return true
1579 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001580#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001581}
1582
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001583bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001584 SkBaseDevice* dev = this->getTopDevice();
1585 // if no device we return false
1586 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001587}
1588
msarettfbfa2582016-08-12 08:29:08 -07001589static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1590#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1591 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1592 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1593 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1594 return 0xF != _mm_movemask_ps(mask);
1595#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1596 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1597 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1598 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1599 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1600#else
1601 SkRect devRectAsRect;
1602 SkRect devClipAsRect;
1603 devRect.store(&devRectAsRect.fLeft);
1604 devClip.store(&devClipAsRect.fLeft);
1605 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1606#endif
1607}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001608
msarettfbfa2582016-08-12 08:29:08 -07001609// It's important for this function to not be inlined. Otherwise the compiler will share code
1610// between the fast path and the slow path, resulting in two slow paths.
1611static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1612 const SkMatrix& matrix) {
1613 SkRect deviceRect;
1614 matrix.mapRect(&deviceRect, src);
1615 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1616}
1617
1618bool SkCanvas::quickReject(const SkRect& src) const {
1619#ifdef SK_DEBUG
1620 // Verify that fDeviceClipBounds are set properly.
1621 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001622 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001623 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001624 } else {
msarettfbfa2582016-08-12 08:29:08 -07001625 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001626 }
msarettfbfa2582016-08-12 08:29:08 -07001627
msarett9637ea92016-08-18 14:03:30 -07001628 // Verify that fIsScaleTranslate is set properly.
1629 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001630#endif
1631
msarett9637ea92016-08-18 14:03:30 -07001632 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001633 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1634 }
1635
1636 // We inline the implementation of mapScaleTranslate() for the fast path.
1637 float sx = fMCRec->fMatrix.getScaleX();
1638 float sy = fMCRec->fMatrix.getScaleY();
1639 float tx = fMCRec->fMatrix.getTranslateX();
1640 float ty = fMCRec->fMatrix.getTranslateY();
1641 Sk4f scale(sx, sy, sx, sy);
1642 Sk4f trans(tx, ty, tx, ty);
1643
1644 // Apply matrix.
1645 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1646
1647 // Make sure left < right, top < bottom.
1648 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1649 Sk4f min = Sk4f::Min(ltrb, rblt);
1650 Sk4f max = Sk4f::Max(ltrb, rblt);
1651 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1652 // ARM this sequence generates the fastest (a single instruction).
1653 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1654
1655 // Check if the device rect is NaN or outside the clip.
1656 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657}
1658
reed@google.com3b3e8952012-08-16 20:53:31 +00001659bool SkCanvas::quickReject(const SkPath& path) const {
1660 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001661}
1662
Mike Klein83c8dd92017-11-28 17:08:45 -05001663SkRect SkCanvas::getLocalClipBounds() const {
1664 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001665 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001666 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001667 }
1668
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001669 SkMatrix inverse;
1670 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001671 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001672 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001673 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001674
Mike Reed42e8c532017-01-23 14:09:13 -05001675 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001676 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001677 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001678
Mike Reedb57b9312018-04-23 12:12:54 -04001679 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001680 inverse.mapRect(&bounds, r);
1681 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001682}
1683
Mike Klein83c8dd92017-11-28 17:08:45 -05001684SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001685 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001686}
1687
reed@android.com8a1c16f2008-12-17 15:59:43 +00001688const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001689 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001690}
1691
Brian Osman11052242016-10-27 14:47:55 -04001692GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001693 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001694 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001695}
1696
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001697GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001698 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001699 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001700}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001701
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001702void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1703 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001704 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001705 if (outer.isEmpty()) {
1706 return;
1707 }
1708 if (inner.isEmpty()) {
1709 this->drawRRect(outer, paint);
1710 return;
1711 }
1712
1713 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001714 // be able to return ...
1715 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001716 //
1717 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001718 if (!outer.getBounds().contains(inner.getBounds())) {
1719 return;
1720 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001721
1722 this->onDrawDRRect(outer, inner, paint);
1723}
1724
reed41af9662015-01-05 07:49:08 -08001725void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001726 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001727 this->onDrawPaint(paint);
1728}
1729
1730void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001731 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001732 // To avoid redundant logic in our culling code and various backends, we always sort rects
1733 // before passing them along.
1734 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001735}
1736
Mike Reedd5674082019-04-19 15:00:47 -04001737void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1738 TRACE_EVENT0("skia", TRACE_FUNC);
1739 this->onDrawBehind(paint);
1740}
1741
msarettdca352e2016-08-26 06:37:45 -07001742void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001743 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001744 if (region.isEmpty()) {
1745 return;
1746 }
1747
1748 if (region.isRect()) {
1749 return this->drawIRect(region.getBounds(), paint);
1750 }
1751
1752 this->onDrawRegion(region, paint);
1753}
1754
reed41af9662015-01-05 07:49:08 -08001755void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001756 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001757 // To avoid redundant logic in our culling code and various backends, we always sort rects
1758 // before passing them along.
1759 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001760}
1761
1762void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001763 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001764 this->onDrawRRect(rrect, paint);
1765}
1766
1767void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001768 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001769 this->onDrawPoints(mode, count, pts, paint);
1770}
1771
Mike Reede88a1cb2017-03-17 09:50:46 -04001772void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1773 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001774 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001775 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001776 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1777 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001778 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001779}
1780
1781void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001782 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001783 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001784 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1785}
1786
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001787void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1788 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001789 TRACE_EVENT0("skia", TRACE_FUNC);
1790 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001791 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001792 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1793}
1794
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001795void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1796 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001797 TRACE_EVENT0("skia", TRACE_FUNC);
1798 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001799 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001800 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001801}
1802
1803void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001804 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001805 this->onDrawPath(path, paint);
1806}
1807
reeda85d4d02015-05-06 12:56:48 -07001808void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001809 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001810 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001811 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001812}
1813
Mike Reedc4e31092018-01-30 11:15:27 -05001814// Returns true if the rect can be "filled" : non-empty and finite
1815static bool fillable(const SkRect& r) {
1816 SkScalar w = r.width();
1817 SkScalar h = r.height();
1818 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1819}
1820
reede47829b2015-08-06 10:02:53 -07001821void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1822 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001823 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001824 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001825 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001826 return;
1827 }
1828 this->onDrawImageRect(image, &src, dst, paint, constraint);
1829}
reed41af9662015-01-05 07:49:08 -08001830
reed84984ef2015-07-17 07:09:43 -07001831void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1832 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001833 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001834 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001835}
1836
Brian Salomonf08002c2018-10-26 16:15:46 -04001837void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001838 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001839 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001840 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001841}
reede47829b2015-08-06 10:02:53 -07001842
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001843namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001844class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001845public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001846 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1847 if (!origPaint) {
1848 return;
1849 }
1850 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1851 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1852 }
1853 if (origPaint->getMaskFilter()) {
1854 fPaint.writable()->setMaskFilter(nullptr);
1855 }
1856 if (origPaint->isAntiAlias()) {
1857 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001858 }
1859 }
1860
1861 const SkPaint* get() const {
1862 return fPaint;
1863 }
1864
1865private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001866 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001867};
1868} // namespace
1869
reed4c21dc52015-06-25 12:32:03 -07001870void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1871 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001872 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001873 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001874 if (dst.isEmpty()) {
1875 return;
1876 }
msarett552bca92016-08-03 06:53:26 -07001877 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001878 LatticePaint latticePaint(paint);
1879 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001880 } else {
reede47829b2015-08-06 10:02:53 -07001881 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001882 }
reed4c21dc52015-06-25 12:32:03 -07001883}
1884
msarett16882062016-08-16 09:31:08 -07001885void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1886 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001887 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001888 RETURN_ON_NULL(image);
1889 if (dst.isEmpty()) {
1890 return;
1891 }
msarett71df2d72016-09-30 12:41:42 -07001892
1893 SkIRect bounds;
1894 Lattice latticePlusBounds = lattice;
1895 if (!latticePlusBounds.fBounds) {
1896 bounds = SkIRect::MakeWH(image->width(), image->height());
1897 latticePlusBounds.fBounds = &bounds;
1898 }
1899
1900 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001901 LatticePaint latticePaint(paint);
1902 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001903 } else {
1904 this->drawImageRect(image, dst, paint);
1905 }
1906}
1907
reed41af9662015-01-05 07:49:08 -08001908void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001909 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001910 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001911 return;
1912 }
reed41af9662015-01-05 07:49:08 -08001913 this->onDrawBitmap(bitmap, dx, dy, paint);
1914}
1915
reede47829b2015-08-06 10:02:53 -07001916void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001917 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001918 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001919 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001920 return;
1921 }
reede47829b2015-08-06 10:02:53 -07001922 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001923}
1924
reed84984ef2015-07-17 07:09:43 -07001925void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1926 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001927 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001928}
1929
reede47829b2015-08-06 10:02:53 -07001930void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1931 SrcRectConstraint constraint) {
1932 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1933 constraint);
1934}
reede47829b2015-08-06 10:02:53 -07001935
reed41af9662015-01-05 07:49:08 -08001936void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1937 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001938 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001939 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001940 return;
1941 }
msarett552bca92016-08-03 06:53:26 -07001942 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001943 LatticePaint latticePaint(paint);
1944 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001945 } else {
reeda5517e22015-07-14 10:54:12 -07001946 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001947 }
reed41af9662015-01-05 07:49:08 -08001948}
1949
msarettc573a402016-08-02 08:05:56 -07001950void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1951 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001952 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001953 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001954 return;
1955 }
msarett71df2d72016-09-30 12:41:42 -07001956
1957 SkIRect bounds;
1958 Lattice latticePlusBounds = lattice;
1959 if (!latticePlusBounds.fBounds) {
1960 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1961 latticePlusBounds.fBounds = &bounds;
1962 }
1963
1964 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001965 LatticePaint latticePaint(paint);
1966 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001967 } else {
msarett16882062016-08-16 09:31:08 -07001968 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001969 }
msarettc573a402016-08-02 08:05:56 -07001970}
1971
reed71c3c762015-06-24 10:29:17 -07001972void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001973 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001974 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001975 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001976 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001977 if (count <= 0) {
1978 return;
1979 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001980 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001981 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001982 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001983}
1984
reedf70b5312016-03-04 16:36:20 -08001985void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001986 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001987 if (key) {
1988 this->onDrawAnnotation(rect, key, value);
1989 }
1990}
1991
reede47829b2015-08-06 10:02:53 -07001992void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1993 const SkPaint* paint, SrcRectConstraint constraint) {
1994 if (src) {
1995 this->drawImageRect(image, *src, dst, paint, constraint);
1996 } else {
1997 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1998 dst, paint, constraint);
1999 }
2000}
2001void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2002 const SkPaint* paint, SrcRectConstraint constraint) {
2003 if (src) {
2004 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2005 } else {
2006 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2007 dst, paint, constraint);
2008 }
2009}
2010
Mike Reed4204da22017-05-17 08:53:36 -04002011void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002012 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04002013 this->onDrawShadowRec(path, rec);
2014}
2015
2016void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
2017 SkPaint paint;
2018 const SkRect& pathBounds = path.getBounds();
2019
Ben Wagner2c312c42018-06-27 14:46:46 -04002020 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04002021 while (iter.next()) {
2022 iter.fDevice->drawShadow(path, rec);
2023 }
2024 LOOPER_END
2025}
2026
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002027void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2028 QuadAAFlags aaFlags, SkColor color, SkBlendMode mode) {
2029 TRACE_EVENT0("skia", TRACE_FUNC);
2030 // Make sure the rect is sorted before passing it along
2031 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2032}
2033
2034void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2035 const SkPoint dstClips[],
2036 const SkMatrix preViewMatrices[],
2037 const SkPaint* paint,
2038 SrcRectConstraint constraint) {
2039 TRACE_EVENT0("skia", TRACE_FUNC);
2040 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2041}
2042
reed@android.com8a1c16f2008-12-17 15:59:43 +00002043//////////////////////////////////////////////////////////////////////////////
2044// These are the virtual drawing methods
2045//////////////////////////////////////////////////////////////////////////////
2046
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002047void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002048 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002049 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2050 }
2051}
2052
reed41af9662015-01-05 07:49:08 -08002053void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002054 this->internalDrawPaint(paint);
2055}
2056
2057void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002058 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002059
2060 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002061 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002062 }
2063
reed@google.com4e2b3d32011-04-07 14:18:59 +00002064 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002065}
2066
reed41af9662015-01-05 07:49:08 -08002067void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2068 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002069 if ((long)count <= 0) {
2070 return;
2071 }
2072
Mike Reed822128b2017-02-28 16:41:03 -05002073 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002074 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002075 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002076 // special-case 2 points (common for drawing a single line)
2077 if (2 == count) {
2078 r.set(pts[0], pts[1]);
2079 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002080 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002081 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002082 if (!r.isFinite()) {
2083 return;
2084 }
Mike Reed822128b2017-02-28 16:41:03 -05002085 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002086 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2087 return;
2088 }
2089 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002090 }
reed@google.coma584aed2012-05-16 14:06:02 +00002091
halcanary96fcdcc2015-08-27 07:41:13 -07002092 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093
Ben Wagner2c312c42018-06-27 14:46:46 -04002094 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002095
reed@android.com8a1c16f2008-12-17 15:59:43 +00002096 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002097 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002098 }
reed@google.com4b226022011-01-11 18:32:13 +00002099
reed@google.com4e2b3d32011-04-07 14:18:59 +00002100 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002101}
2102
reed4a167172016-08-18 17:15:25 -07002103static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2104 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07002105 (intptr_t)paint.getLooper() ) != 0;
2106}
2107
reed41af9662015-01-05 07:49:08 -08002108void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002109 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002110 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002111 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002112 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002113 return;
2114 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002115 }
reed@google.com4b226022011-01-11 18:32:13 +00002116
reed4a167172016-08-18 17:15:25 -07002117 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002118 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002119
reed4a167172016-08-18 17:15:25 -07002120 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002121 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002122 }
2123
2124 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002125 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002126 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002127 SkDrawIter iter(this);
2128 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002129 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002130 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002131 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002132}
2133
msarett44df6512016-08-25 13:54:30 -07002134void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002135 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002136 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002137 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002138 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2139 return;
2140 }
msarett44df6512016-08-25 13:54:30 -07002141 }
2142
Ben Wagner2c312c42018-06-27 14:46:46 -04002143 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002144
2145 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002146 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002147 }
2148
2149 LOOPER_END
2150}
2151
Mike Reedd5674082019-04-19 15:00:47 -04002152void SkCanvas::onDrawBehind(const SkPaint& paint) {
2153 SkIRect bounds;
2154 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2155 for (;;) {
2156 const MCRec* rec = (const MCRec*)iter.prev();
2157 if (!rec) {
2158 return; // no backimages, so nothing to draw
2159 }
2160 if (rec->fBackImage) {
2161 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2162 rec->fBackImage->fImage->width(),
2163 rec->fBackImage->fImage->height());
2164 break;
2165 }
2166 }
2167
2168 LOOPER_BEGIN(paint, nullptr)
2169
2170 while (iter.next()) {
2171 SkBaseDevice* dev = iter.fDevice;
2172
Mike Reedd5674082019-04-19 15:00:47 -04002173 dev->save();
2174 // We use clipRegion because it is already defined to operate in dev-space
2175 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2176 // but we don't want that, so we undo that before calling in.
2177 SkRegion rgn(bounds.makeOffset(dev->fOrigin.fX, dev->fOrigin.fY));
2178 dev->clipRegion(rgn, SkClipOp::kIntersect);
2179 dev->drawPaint(looper.paint());
Mike Reed9adc82c2019-04-23 10:28:13 -04002180 dev->restore(fMCRec->fMatrix);
Mike Reedd5674082019-04-19 15:00:47 -04002181 }
2182
2183 LOOPER_END
2184}
2185
reed41af9662015-01-05 07:49:08 -08002186void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002187 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002188 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002189 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002190 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002191 return;
2192 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002193 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002194
Ben Wagner2c312c42018-06-27 14:46:46 -04002195 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002196
2197 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002198 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002199 }
2200
2201 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002202}
2203
bsalomonac3aa242016-08-19 11:25:19 -07002204void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2205 SkScalar sweepAngle, bool useCenter,
2206 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002207 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002208 if (paint.canComputeFastBounds()) {
2209 SkRect storage;
2210 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002211 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002212 return;
2213 }
bsalomonac3aa242016-08-19 11:25:19 -07002214 }
2215
Ben Wagner2c312c42018-06-27 14:46:46 -04002216 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002217
2218 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002219 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002220 }
2221
2222 LOOPER_END
2223}
2224
reed41af9662015-01-05 07:49:08 -08002225void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002226 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002227 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002228 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2229 return;
2230 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002231 }
2232
2233 if (rrect.isRect()) {
2234 // call the non-virtual version
2235 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002236 return;
2237 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002238 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002239 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2240 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002241 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002242
Ben Wagner2c312c42018-06-27 14:46:46 -04002243 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002244
2245 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002246 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002247 }
2248
2249 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002250}
2251
Mike Reed822128b2017-02-28 16:41:03 -05002252void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002253 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002254 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002255 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2256 return;
2257 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002258 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002259
Ben Wagner2c312c42018-06-27 14:46:46 -04002260 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002261
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002262 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002263 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002264 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002265
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002266 LOOPER_END
2267}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002268
reed41af9662015-01-05 07:49:08 -08002269void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002270 if (!path.isFinite()) {
2271 return;
2272 }
2273
Mike Reed822128b2017-02-28 16:41:03 -05002274 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002275 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002276 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002277 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2278 return;
2279 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002280 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002281
Mike Reed822128b2017-02-28 16:41:03 -05002282 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002283 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002284 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002285 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002286 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002287 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002288
Ben Wagner2c312c42018-06-27 14:46:46 -04002289 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290
2291 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002292 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002293 }
2294
reed@google.com4e2b3d32011-04-07 14:18:59 +00002295 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002296}
2297
reed262a71b2015-12-05 13:07:27 -08002298bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002299 if (!paint.getImageFilter()) {
2300 return false;
2301 }
2302
2303 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002304 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002305 return false;
2306 }
2307
2308 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2309 // Once we can filter and the filter will return a result larger than itself, we should be
2310 // able to remove this constraint.
2311 // skbug.com/4526
2312 //
2313 SkPoint pt;
2314 ctm.mapXY(x, y, &pt);
2315 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2316 return ir.contains(fMCRec->fRasterClip.getBounds());
2317}
2318
Mike Reedf441cfc2018-04-11 14:50:16 -04002319// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2320// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2321// null.
2322static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2323 if (paintParam) {
2324 *real = *paintParam;
2325 real->setStyle(SkPaint::kFill_Style);
2326 real->setPathEffect(nullptr);
2327 paintParam = real;
2328 }
2329 return paintParam;
2330}
2331
reeda85d4d02015-05-06 12:56:48 -07002332void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002333 SkPaint realPaint;
2334 paint = init_image_paint(&realPaint, paint);
2335
reeda85d4d02015-05-06 12:56:48 -07002336 SkRect bounds = SkRect::MakeXYWH(x, y,
2337 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002338 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002339 SkRect tmp = bounds;
2340 if (paint) {
2341 paint->computeFastBounds(tmp, &tmp);
2342 }
2343 if (this->quickReject(tmp)) {
2344 return;
2345 }
reeda85d4d02015-05-06 12:56:48 -07002346 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002347 // At this point we need a real paint object. If the caller passed null, then we should
2348 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2349 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2350 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002351
reeda2217ef2016-07-20 06:04:34 -07002352 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002353 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2354 *paint);
2355 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002356 special = this->getDevice()->makeSpecial(image);
2357 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002358 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002359 }
2360 }
2361
reed262a71b2015-12-05 13:07:27 -08002362 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2363
reeda85d4d02015-05-06 12:56:48 -07002364 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002365 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002366 if (special) {
2367 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002368 iter.fDevice->ctm().mapXY(x, y, &pt);
2369 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002370 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002371 SkScalarRoundToInt(pt.fY), pnt,
2372 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002373 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002374 iter.fDevice->drawImageRect(
2375 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2376 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002377 }
reeda85d4d02015-05-06 12:56:48 -07002378 }
halcanary9d524f22016-03-29 09:03:52 -07002379
reeda85d4d02015-05-06 12:56:48 -07002380 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002381}
2382
reed41af9662015-01-05 07:49:08 -08002383void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002384 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002385 SkPaint realPaint;
2386 paint = init_image_paint(&realPaint, paint);
2387
halcanary96fcdcc2015-08-27 07:41:13 -07002388 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002389 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002390 if (paint) {
2391 paint->computeFastBounds(dst, &storage);
2392 }
2393 if (this->quickReject(storage)) {
2394 return;
2395 }
reeda85d4d02015-05-06 12:56:48 -07002396 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002397 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002398
Ben Wagner2c312c42018-06-27 14:46:46 -04002399 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002400
reeda85d4d02015-05-06 12:56:48 -07002401 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002402 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002403 }
halcanary9d524f22016-03-29 09:03:52 -07002404
reeda85d4d02015-05-06 12:56:48 -07002405 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002406}
2407
reed41af9662015-01-05 07:49:08 -08002408void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002409 SkDEBUGCODE(bitmap.validate();)
2410
reed33366972015-10-08 09:22:02 -07002411 if (bitmap.drawsNothing()) {
2412 return;
2413 }
2414
Mike Reedf441cfc2018-04-11 14:50:16 -04002415 SkPaint realPaint;
2416 init_image_paint(&realPaint, paint);
2417 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002418
Mike Reed822128b2017-02-28 16:41:03 -05002419 SkRect bounds;
2420 bitmap.getBounds(&bounds);
2421 bounds.offset(x, y);
2422 bool canFastBounds = paint->canComputeFastBounds();
2423 if (canFastBounds) {
2424 SkRect storage;
2425 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002426 return;
2427 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002428 }
reed@google.com4b226022011-01-11 18:32:13 +00002429
reeda2217ef2016-07-20 06:04:34 -07002430 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002431 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2432 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002433 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002434 special = this->getDevice()->makeSpecial(bitmap);
2435 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002436 drawAsSprite = false;
2437 }
2438 }
2439
Mike Reed822128b2017-02-28 16:41:03 -05002440 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002441
2442 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002443 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002444 if (special) {
reed262a71b2015-12-05 13:07:27 -08002445 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002446 iter.fDevice->ctm().mapXY(x, y, &pt);
2447 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002448 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002449 SkScalarRoundToInt(pt.fY), pnt,
2450 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002451 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002452 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2453 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2454 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002455 }
reed33366972015-10-08 09:22:02 -07002456 }
msarettfbfa2582016-08-12 08:29:08 -07002457
reed33366972015-10-08 09:22:02 -07002458 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459}
2460
reed@google.com9987ec32011-09-07 11:57:52 +00002461// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002462void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002463 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002464 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002465 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466 return;
2467 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002468
halcanary96fcdcc2015-08-27 07:41:13 -07002469 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002470 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002471 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2472 return;
2473 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474 }
reed@google.com3d608122011-11-21 15:16:16 +00002475
reed@google.com33535f32012-09-25 15:37:50 +00002476 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002477 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002478 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002479 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002480
Ben Wagner2c312c42018-06-27 14:46:46 -04002481 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002482
reed@google.com33535f32012-09-25 15:37:50 +00002483 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002484 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002485 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002486
reed@google.com33535f32012-09-25 15:37:50 +00002487 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488}
2489
reed41af9662015-01-05 07:49:08 -08002490void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002491 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002492 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002493 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002494}
2495
reed4c21dc52015-06-25 12:32:03 -07002496void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2497 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002498 SkPaint realPaint;
2499 paint = init_image_paint(&realPaint, paint);
2500
halcanary96fcdcc2015-08-27 07:41:13 -07002501 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002502 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002503 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2504 return;
2505 }
reed@google.com3d608122011-11-21 15:16:16 +00002506 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002507 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002508
Ben Wagner2c312c42018-06-27 14:46:46 -04002509 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002510
reed4c21dc52015-06-25 12:32:03 -07002511 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002512 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002513 }
halcanary9d524f22016-03-29 09:03:52 -07002514
reed4c21dc52015-06-25 12:32:03 -07002515 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002516}
2517
reed41af9662015-01-05 07:49:08 -08002518void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2519 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002520 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002521 SkPaint realPaint;
2522 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002523
halcanary96fcdcc2015-08-27 07:41:13 -07002524 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002525 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002526 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2527 return;
2528 }
reed4c21dc52015-06-25 12:32:03 -07002529 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002530 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002531
Ben Wagner2c312c42018-06-27 14:46:46 -04002532 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002533
reed4c21dc52015-06-25 12:32:03 -07002534 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002535 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002536 }
halcanary9d524f22016-03-29 09:03:52 -07002537
reed4c21dc52015-06-25 12:32:03 -07002538 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002539}
2540
msarett16882062016-08-16 09:31:08 -07002541void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2542 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002543 SkPaint realPaint;
2544 paint = init_image_paint(&realPaint, paint);
2545
msarett16882062016-08-16 09:31:08 -07002546 if (nullptr == paint || paint->canComputeFastBounds()) {
2547 SkRect storage;
2548 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2549 return;
2550 }
2551 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002552 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002553
Ben Wagner2c312c42018-06-27 14:46:46 -04002554 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002555
2556 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002557 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002558 }
2559
2560 LOOPER_END
2561}
2562
2563void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2564 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002565 SkPaint realPaint;
2566 paint = init_image_paint(&realPaint, paint);
2567
msarett16882062016-08-16 09:31:08 -07002568 if (nullptr == paint || paint->canComputeFastBounds()) {
2569 SkRect storage;
2570 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2571 return;
2572 }
2573 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002574 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002575
Ben Wagner2c312c42018-06-27 14:46:46 -04002576 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002577
2578 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002579 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002580 }
2581
2582 LOOPER_END
2583}
2584
fmalita00d5c2c2014-08-21 08:53:26 -07002585void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2586 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002587 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002588 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002589 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002590 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002591 SkRect tmp;
2592 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2593 return;
2594 }
2595 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002596 }
2597
fmalita024f9962015-03-03 19:08:17 -08002598 // We cannot filter in the looper as we normally do, because the paint is
2599 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002600 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002601
fmalitaaa1b9122014-08-28 14:32:24 -07002602 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002603 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002604 }
2605
fmalitaaa1b9122014-08-28 14:32:24 -07002606 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002607}
2608
Mike Reed358fcad2018-11-23 15:27:51 -05002609// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002610void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002611 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2612 TRACE_EVENT0("skia", TRACE_FUNC);
2613 if (byteLength) {
2614 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002615 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002616 }
2617}
Mike Reed4f81bb72019-01-23 09:23:00 -05002618
fmalita00d5c2c2014-08-21 08:53:26 -07002619void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2620 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002621 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002622 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002623 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002624 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002625}
reed@google.come0d9ce82014-04-23 04:00:17 +00002626
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002627void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002628 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002629 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002630
2631 while (iter.next()) {
2632 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002633 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002634 }
2635
2636 LOOPER_END
2637}
2638
dandovb3c9d1c2014-08-12 08:34:29 -07002639void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002640 const SkPoint texCoords[4], SkBlendMode bmode,
2641 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002642 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002643 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002644 return;
2645 }
mtklein6cfa73a2014-08-13 13:33:49 -07002646
Mike Reedfaba3712016-11-03 14:45:31 -04002647 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002648}
2649
2650void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002651 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002652 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002653 // Since a patch is always within the convex hull of the control points, we discard it when its
2654 // bounding rectangle is completely outside the current clip.
2655 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002656 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002657 if (this->quickReject(bounds)) {
2658 return;
2659 }
mtklein6cfa73a2014-08-13 13:33:49 -07002660
Ben Wagner2c312c42018-06-27 14:46:46 -04002661 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002662
dandovecfff212014-08-04 10:02:00 -07002663 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002664 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002665 }
mtklein6cfa73a2014-08-13 13:33:49 -07002666
dandovecfff212014-08-04 10:02:00 -07002667 LOOPER_END
2668}
2669
reeda8db7282015-07-07 10:22:31 -07002670void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002671#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002672 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002673#endif
reede3b38ce2016-01-08 09:18:44 -08002674 RETURN_ON_NULL(dr);
2675 if (x || y) {
2676 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2677 this->onDrawDrawable(dr, &matrix);
2678 } else {
2679 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002680 }
2681}
2682
reeda8db7282015-07-07 10:22:31 -07002683void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002684#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002685 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002686#endif
reede3b38ce2016-01-08 09:18:44 -08002687 RETURN_ON_NULL(dr);
2688 if (matrix && matrix->isIdentity()) {
2689 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002690 }
reede3b38ce2016-01-08 09:18:44 -08002691 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002692}
2693
2694void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002695 // drawable bounds are no longer reliable (e.g. android displaylist)
2696 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002697 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002698}
2699
reed71c3c762015-06-24 10:29:17 -07002700void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002701 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002702 const SkRect* cull, const SkPaint* paint) {
2703 if (cull && this->quickReject(*cull)) {
2704 return;
2705 }
2706
2707 SkPaint pnt;
2708 if (paint) {
2709 pnt = *paint;
2710 }
halcanary9d524f22016-03-29 09:03:52 -07002711
Ben Wagner2c312c42018-06-27 14:46:46 -04002712 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002713 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002714 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002715 }
2716 LOOPER_END
2717}
2718
reedf70b5312016-03-04 16:36:20 -08002719void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2720 SkASSERT(key);
2721
2722 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002723 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002724 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002725 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002726 }
2727 LOOPER_END
2728}
2729
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002730void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2731 SkColor color, SkBlendMode mode) {
2732 SkASSERT(r.isSorted());
2733
2734 // If this used a paint, it would be a filled color with blend mode, which does not
2735 // need to use an autodraw loop, so use SkDrawIter directly.
2736 if (this->quickReject(r)) {
2737 return;
2738 }
2739
2740 this->predrawNotify();
2741 SkDrawIter iter(this);
2742 while(iter.next()) {
2743 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2744 }
2745}
2746
2747void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2748 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2749 const SkPaint* paint, SrcRectConstraint constraint) {
2750 SkPaint realPaint;
2751 init_image_paint(&realPaint, paint);
2752
2753 // Looper is used when there are image filters, which drawEdgeAAImageSet needs to support
2754 // for Chromium's RenderPassDrawQuads' filters.
2755 LOOPER_BEGIN(realPaint, nullptr)
2756 while (iter.next()) {
2757 iter.fDevice->drawEdgeAAImageSet(
2758 imageSet, count, dstClips, preViewMatrices, looper.paint(), constraint);
2759 }
2760 LOOPER_END
2761}
2762
reed@android.com8a1c16f2008-12-17 15:59:43 +00002763//////////////////////////////////////////////////////////////////////////////
2764// These methods are NOT virtual, and therefore must call back into virtual
2765// methods, rather than actually drawing themselves.
2766//////////////////////////////////////////////////////////////////////////////
2767
reed374772b2016-10-05 17:33:02 -07002768void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002771 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772 this->drawPaint(paint);
2773}
2774
2775void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002776 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2778}
2779
Mike Reed3661bc92017-02-22 13:21:42 -05002780void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782 pts[0].set(x0, y0);
2783 pts[1].set(x1, y1);
2784 this->drawPoints(kLines_PointMode, 2, pts, paint);
2785}
2786
Mike Reed3661bc92017-02-22 13:21:42 -05002787void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002788 if (radius < 0) {
2789 radius = 0;
2790 }
2791
2792 SkRect r;
2793 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002794 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795}
2796
2797void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2798 const SkPaint& paint) {
2799 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002800 SkRRect rrect;
2801 rrect.setRectXY(r, rx, ry);
2802 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002803 } else {
2804 this->drawRect(r, paint);
2805 }
2806}
2807
reed@android.com8a1c16f2008-12-17 15:59:43 +00002808void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2809 SkScalar sweepAngle, bool useCenter,
2810 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002811 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002812 if (oval.isEmpty() || !sweepAngle) {
2813 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814 }
bsalomon21af9ca2016-08-25 12:29:23 -07002815 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816}
2817
reed@android.comf76bacf2009-05-13 14:00:33 +00002818///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002819#ifdef SK_DISABLE_SKPICTURE
2820void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002821
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002822
2823void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2824 const SkPaint* paint) {}
2825#else
Mike Klein88d90712018-01-27 17:30:04 +00002826/**
2827 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2828 * against the playback cost of recursing into the subpicture to get at its actual ops.
2829 *
2830 * For now we pick a conservatively small value, though measurement (and other heuristics like
2831 * the type of ops contained) may justify changing this value.
2832 */
2833#define kMaxPictureOpsToUnrollInsteadOfRef 1
2834
reedd5fa1a42014-08-09 11:08:05 -07002835void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002836 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002837 RETURN_ON_NULL(picture);
2838
reede3b38ce2016-01-08 09:18:44 -08002839 if (matrix && matrix->isIdentity()) {
2840 matrix = nullptr;
2841 }
Mike Klein88d90712018-01-27 17:30:04 +00002842 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2843 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2844 picture->playback(this);
2845 } else {
2846 this->onDrawPicture(picture, matrix, paint);
2847 }
reedd5fa1a42014-08-09 11:08:05 -07002848}
robertphillips9b14f262014-06-04 05:40:44 -07002849
reedd5fa1a42014-08-09 11:08:05 -07002850void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2851 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002852 if (!paint || paint->canComputeFastBounds()) {
2853 SkRect bounds = picture->cullRect();
2854 if (paint) {
2855 paint->computeFastBounds(bounds, &bounds);
2856 }
2857 if (matrix) {
2858 matrix->mapRect(&bounds);
2859 }
2860 if (this->quickReject(bounds)) {
2861 return;
2862 }
2863 }
2864
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002865 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002866 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002867}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002868#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002869
reed@android.com8a1c16f2008-12-17 15:59:43 +00002870///////////////////////////////////////////////////////////////////////////////
2871///////////////////////////////////////////////////////////////////////////////
2872
reed3aafe112016-08-18 12:45:34 -07002873SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002874 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002875
2876 SkASSERT(canvas);
2877
reed3aafe112016-08-18 12:45:34 -07002878 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002879 fDone = !fImpl->next();
2880}
2881
2882SkCanvas::LayerIter::~LayerIter() {
2883 fImpl->~SkDrawIter();
2884}
2885
2886void SkCanvas::LayerIter::next() {
2887 fDone = !fImpl->next();
2888}
2889
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002890SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002891 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002892}
2893
2894const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002895 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002896}
2897
2898const SkPaint& SkCanvas::LayerIter::paint() const {
2899 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002900 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002901 paint = &fDefaultPaint;
2902 }
2903 return *paint;
2904}
2905
Mike Reedca37f322018-03-08 13:22:16 -05002906SkIRect SkCanvas::LayerIter::clipBounds() const {
2907 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002908}
2909
reed@android.com8a1c16f2008-12-17 15:59:43 +00002910int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2911int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002912
2913///////////////////////////////////////////////////////////////////////////////
2914
Brian Osmane8a98632019-04-10 10:26:10 -04002915SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2916SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2917SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2918SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2919
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002920SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2921 const SkRect& dstRect, int matrixIndex, float alpha,
2922 unsigned aaFlags, bool hasClip)
2923 : fImage(std::move(image))
2924 , fSrcRect(srcRect)
2925 , fDstRect(dstRect)
2926 , fMatrixIndex(matrixIndex)
2927 , fAlpha(alpha)
2928 , fAAFlags(aaFlags)
2929 , fHasClip(hasClip) {}
2930
2931SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2932 const SkRect& dstRect, float alpha, unsigned aaFlags)
2933 : fImage(std::move(image))
2934 , fSrcRect(srcRect)
2935 , fDstRect(dstRect)
2936 , fAlpha(alpha)
2937 , fAAFlags(aaFlags) {}
2938
2939///////////////////////////////////////////////////////////////////////////////
2940
Mike Reed5df49342016-11-12 08:06:55 -06002941std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002942 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002943 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002944 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002945 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002946
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002947 SkBitmap bitmap;
2948 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002949 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002950 }
Mike Reed12f77342017-11-08 11:19:52 -05002951
2952 return props ?
2953 skstd::make_unique<SkCanvas>(bitmap, *props) :
2954 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002955}
reedd5fa1a42014-08-09 11:08:05 -07002956
2957///////////////////////////////////////////////////////////////////////////////
2958
Florin Malitaee424ac2016-12-01 12:47:59 -05002959SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002960 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002961
Florin Malita439ace92016-12-02 12:05:41 -05002962SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002963 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002964
Herb Derbyefe39bc2018-05-01 17:06:20 -04002965SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002966 : INHERITED(device) {}
2967
Florin Malitaee424ac2016-12-01 12:47:59 -05002968SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2969 (void)this->INHERITED::getSaveLayerStrategy(rec);
2970 return kNoLayer_SaveLayerStrategy;
2971}
2972
Mike Reed148b7fd2018-12-18 17:38:18 -05002973bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2974 return false;
2975}
2976
Florin Malitaee424ac2016-12-01 12:47:59 -05002977///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002978
reed73603f32016-09-20 08:42:38 -07002979static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2980static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2981static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2982static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2983static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2984static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002985
2986///////////////////////////////////////////////////////////////////////////////////////////////////
2987
2988SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2989 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002990 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002991 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2992 SkIPoint origin = dev->getOrigin();
2993 SkMatrix ctm = this->getTotalMatrix();
2994 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2995
2996 SkIRect clip = fMCRec->fRasterClip.getBounds();
2997 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002998 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002999 clip.setEmpty();
3000 }
3001
3002 fAllocator->updateHandle(handle, ctm, clip);
3003 return handle;
3004 }
3005 return nullptr;
3006}
3007
3008static bool install(SkBitmap* bm, const SkImageInfo& info,
3009 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04003010 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05003011}
3012
3013SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3014 SkBitmap* bm) {
3015 SkRasterHandleAllocator::Rec rec;
3016 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3017 return nullptr;
3018 }
3019 return rec.fHandle;
3020}
3021
3022std::unique_ptr<SkCanvas>
3023SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3024 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04003025 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05003026 return nullptr;
3027 }
3028
3029 SkBitmap bm;
3030 Handle hndl;
3031
3032 if (rec) {
3033 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3034 } else {
3035 hndl = alloc->allocBitmap(info, &bm);
3036 }
3037 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3038}
Mike Reed7c9c9e42018-01-03 09:23:34 -05003039
3040///////////////////////////////////////////////////////////////////////////////////////////////////
3041
3042