blob: 251e71b299bfca82d90c39999c983cda49e4a4fe [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) {
Michael Ludwigaa861a12019-07-19 10:13:47 -0400831 // clipRectBounds() is called to determine the input layer size needed for a given image filter.
832 // The coordinate space of the rectangle passed to filterBounds(kReverse) is meant to be in the
833 // filtering layer space. Here, 'clipBounds' is always in the true device space. When an image
834 // filter does not require a decomposed CTM matrix, the filter space and device space are the
835 // same. When it has been decomposed, we want the original image filter node to process the
836 // bounds in the layer space represented by the decomposed scale matrix. 'imageFilter' is no
837 // longer the original filter, but has the remainder matrix baked into it, and passing in the
838 // the true device clip bounds ensures that the matrix image filter provides a layer clip bounds
839 // to the original filter node (barring inflation from consecutive calls to mapRect). While
840 // initially counter-intuitive given the apparent inconsistency of coordinate spaces, always
841 // passing getDeviceClipBounds() to 'imageFilter' is correct.
842 // FIXME (michaelludwig) - When the remainder matrix is instead applied as a final draw, it will
843 // be important to more accurately calculate the clip bounds in the layer space for the original
844 // image filter (similar to how matrix image filter does it, but ideally without the inflation).
Mike Reed918e1442017-01-23 11:39:45 -0500845 SkIRect clipBounds = this->getDeviceClipBounds();
846 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000847 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000848 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000849
reed96e657d2015-03-10 17:30:07 -0700850 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
851
Robert Phillips12078432018-05-17 11:17:39 -0400852 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
853 // If the image filter DAG affects transparent black then we will need to render
854 // out to the clip bounds
855 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000856 }
Robert Phillips12078432018-05-17 11:17:39 -0400857
858 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700859 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000860 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700861 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400862 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000863 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400864 inputSaveLayerBounds = clipBounds;
865 }
866
867 if (imageFilter) {
868 // expand the clip bounds by the image filter DAG to include extra content that might
869 // be required by the image filters.
870 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
871 SkImageFilter::kReverse_MapDirection,
872 &inputSaveLayerBounds);
873 }
874
875 SkIRect clippedSaveLayerBounds;
876 if (bounds) {
877 // For better or for worse, user bounds currently act as a hard clip on the layer's
878 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
879 clippedSaveLayerBounds = inputSaveLayerBounds;
880 } else {
881 // If there are no user bounds, we don't want to artificially restrict the resulting
882 // layer bounds, so allow the expanded clip bounds free reign.
883 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000884 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800885
886 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400887 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800888 if (BoundsAffectsClip(saveLayerFlags)) {
889 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
890 fMCRec->fRasterClip.setEmpty();
891 fDeviceClipBounds.setEmpty();
892 }
893 return false;
894 }
Robert Phillips12078432018-05-17 11:17:39 -0400895 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896
reed4960eee2015-12-18 07:09:18 -0800897 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700898 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400899 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
900 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000901 }
902
903 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400904 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000905 }
Robert Phillips12078432018-05-17 11:17:39 -0400906
junov@chromium.orga907ac32012-02-24 21:54:07 +0000907 return true;
908}
909
reed4960eee2015-12-18 07:09:18 -0800910int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
911 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000912}
913
Cary Clarke041e312018-03-06 13:00:52 -0500914int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700915 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400916 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
917 // no need for the layer (or any of the draws until the matching restore()
918 this->save();
919 this->clipRect({0,0,0,0});
920 } else {
921 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
922 fSaveCount += 1;
923 this->internalSaveLayer(rec, strategy);
924 }
reed4960eee2015-12-18 07:09:18 -0800925 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800926}
927
Mike Reed148b7fd2018-12-18 17:38:18 -0500928int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
929 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
930 // Assuming clips never expand, if the request bounds is outside of the current clip
931 // there is no need to copy/restore the area, so just devolve back to a regular save.
932 this->save();
933 } else {
934 bool doTheWork = this->onDoSaveBehind(bounds);
935 fSaveCount += 1;
936 this->internalSave();
937 if (doTheWork) {
938 this->internalSaveBehind(bounds);
939 }
940 }
941 return this->getSaveCount() - 1;
942}
943
reeda2217ef2016-07-20 06:04:34 -0700944void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500945 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500946 const SkMatrix& ctm) {
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400947 SkPaint p;
Michael Ludwig08b260c2019-05-17 11:21:53 -0400948 SkIRect snapBounds = SkIRect::MakeXYWH(dstOrigin.x() - src->getOrigin().x(),
949 dstOrigin.y() - src->getOrigin().y(),
950 dst->width(), dst->height());
951 int x = 0;
952 int y = 0;
953
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400954 if (filter) {
Michael Ludwig08b260c2019-05-17 11:21:53 -0400955 // Calculate expanded snap bounds
956 SkIRect newBounds = filter->filterBounds(
957 snapBounds, ctm, SkImageFilter::kReverse_MapDirection, &snapBounds);
958 // Must clamp to valid src since the filter or rotations may expand beyond what's readable
959 SkIRect srcR = SkIRect::MakeWH(src->width(), src->height());
960 if (!newBounds.intersect(srcR)) {
961 return;
962 }
963
964 x = newBounds.fLeft - snapBounds.fLeft;
965 y = newBounds.fTop - snapBounds.fTop;
966 snapBounds = newBounds;
967
968 SkMatrix localCTM;
969 sk_sp<SkImageFilter> modifiedFilter = SkApplyCTMToBackdropFilter(filter, ctm, &localCTM);
970 // Account for the origin offset in the CTM
971 localCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
972
973 // In this case we always wrap the filter (even when it's the original) with 'localCTM'
974 // since there's no device CTM stack that provides it to the image filter context.
975 // FIXME skbug.com/9074 - once perspective is properly supported, drop the
976 // localCTM.hasPerspective condition from assert.
977 SkASSERT(localCTM.isScaleTranslate() || filter->canHandleComplexCTM() ||
978 localCTM.hasPerspective());
979 p.setImageFilter(modifiedFilter->makeWithLocalMatrix(localCTM));
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400980 }
981
Michael Ludwig08b260c2019-05-17 11:21:53 -0400982 auto special = src->snapBackImage(snapBounds);
reeda2217ef2016-07-20 06:04:34 -0700983 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400984 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700985 }
robertphillips7354a4b2015-12-16 05:08:27 -0800986}
reed70ee31b2015-12-10 13:44:45 -0800987
Mike Reed25394292019-03-07 09:36:36 -0500988// This is shared by all backends, but contains raster-specific thoughts. Can we defer to the
989// device to perform this?
Mike Kleine083f7c2018-02-07 12:54:27 -0500990static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500991 // Need to force L32 for now if we have an image filter.
Mike Reed25394292019-03-07 09:36:36 -0500992 // If filters ever support other colortypes, e.g. F16, we can modify this check.
Mike Klein649fb732018-02-26 15:09:16 -0500993 if (paint && paint->getImageFilter()) {
Mike Reed25394292019-03-07 09:36:36 -0500994 // TODO: can we query the imagefilter, to see if it can handle floats (so we don't always
995 // use N32 when the layer itself was float)?
996 return SkImageInfo::MakeN32Premul(w, h, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800997 }
Mike Klein649fb732018-02-26 15:09:16 -0500998
999 SkColorType ct = prev.colorType();
1000 if (prev.bytesPerPixel() <= 4) {
1001 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
1002 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
1003 ct = kN32_SkColorType;
1004 }
1005 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001006}
1007
reed4960eee2015-12-18 07:09:18 -08001008void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -07001009 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -08001010 const SkRect* bounds = rec.fBounds;
1011 const SkPaint* paint = rec.fPaint;
1012 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1013
Mike Reed5532c2a2019-02-23 12:00:32 -05001014 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
1015 // regardless of any hint-rect from the caller. skbug.com/8783
1016 if (rec.fBackdrop) {
1017 bounds = nullptr;
1018 }
1019
reed8c30a812016-04-20 16:36:51 -07001020 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001021 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001022 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -04001023 MCRec* modifiedRec = nullptr;
Michael Ludwig08b260c2019-05-17 11:21:53 -04001024
reed8c30a812016-04-20 16:36:51 -07001025 /*
Michael Ludwig08b260c2019-05-17 11:21:53 -04001026 * Many ImageFilters (so far) do not (on their own) correctly handle matrices (CTM) that
1027 * contain rotation/skew/etc. We rely on applyCTM to create a new image filter DAG as needed to
1028 * accommodate this, but it requires update the CTM we use when drawing into the layer.
reed8c30a812016-04-20 16:36:51 -07001029 *
1030 * 1. Stash off the current CTM
Michael Ludwig08b260c2019-05-17 11:21:53 -04001031 * 2. Apply the CTM to imagefilter, which decomposes it into simple and complex transforms
1032 * if necessary.
1033 * 3. Wack the CTM to be the remaining scale matrix and use the modified imagefilter, which
1034 * is a MatrixImageFilter that contains the complex matrix.
reed8c30a812016-04-20 16:36:51 -07001035 * 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 -04001036 * 5. During restore, the MatrixImageFilter automatically applies complex stage to the output
reed8c30a812016-04-20 16:36:51 -07001037 * of the original imagefilter, and draw that (via drawSprite)
1038 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1039 *
1040 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1041 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1042 */
Michael Ludwig08b260c2019-05-17 11:21:53 -04001043 if (imageFilter) {
1044 SkMatrix modifiedCTM;
1045 sk_sp<SkImageFilter> modifiedFilter = SkApplyCTMToFilter(imageFilter, stashedMatrix,
1046 &modifiedCTM);
1047 if (!SkIsSameFilter(modifiedFilter.get(), imageFilter)) {
1048 // The original filter couldn't support the CTM entirely
1049 SkASSERT(modifiedCTM.isScaleTranslate() || imageFilter->canHandleComplexCTM());
1050 modifiedRec = fMCRec;
1051 this->internalSetMatrix(modifiedCTM);
1052 SkPaint* p = lazyP.set(*paint);
1053 p->setImageFilter(std::move(modifiedFilter));
1054 imageFilter = p->getImageFilter();
1055 paint = p;
1056 }
1057 // Else the filter didn't change, so modifiedCTM == stashedMatrix and there's nothing
1058 // left to do since the stack already has that as the CTM.
reed8c30a812016-04-20 16:36:51 -07001059 }
reed8c30a812016-04-20 16:36:51 -07001060
junov@chromium.orga907ac32012-02-24 21:54:07 +00001061 // do this before we create the layer. We don't call the public save() since
1062 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001063 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001064
junov@chromium.orga907ac32012-02-24 21:54:07 +00001065 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001066 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001067 if (modifiedRec) {
1068 // In this case there will be no layer in which to stash the matrix so we need to
1069 // revert the prior MCRec to its earlier state.
1070 modifiedRec->fMatrix = stashedMatrix;
1071 }
reed2ff1fce2014-12-11 07:07:37 -08001072 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073 }
1074
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001075 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1076 // the clipRectBounds() call above?
1077 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001078 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001079 }
1080
reed8dc0ccb2015-03-20 06:32:52 -07001081 SkPixelGeometry geo = fProps.pixelGeometry();
1082 if (paint) {
reed76033be2015-03-14 10:54:31 -07001083 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001084 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001085 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001086 }
1087 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088
robertphillips5139e502016-07-19 05:10:40 -07001089 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001090 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001091 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001092 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001093 }
reedb2db8982014-11-13 12:41:02 -08001094
Mike Kleine083f7c2018-02-07 12:54:27 -05001095 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
Mike Reed1f3548c2019-07-12 12:53:11 -04001096 if (rec.fSaveLayerFlags & kF16ColorType) {
1097 info = info.makeColorType(kRGBA_F16_SkColorType);
1098 }
reed129ed1c2016-02-22 06:42:31 -08001099
Hal Canary704cd322016-11-07 14:13:52 -05001100 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001101 {
Florin Malita07e4adf2019-01-07 16:34:18 -05001102 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType();
reeddaa57bf2015-05-15 10:39:17 -07001103 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001104 const bool trackCoverage =
1105 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001106 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001107 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001108 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001109 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001110 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1111 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001112 return;
reed61f501f2015-04-29 08:34:00 -07001113 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001114 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001115 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001116
Mike Reedb43a3e02017-02-11 10:18:58 -05001117 // only have a "next" if this new layer doesn't affect the clip (rare)
1118 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001119 fMCRec->fLayer = layer;
1120 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001121
Mike Reedc61abee2017-02-28 17:45:27 -05001122 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001123 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001124 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001125 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001126
Mike Reedc42a1cd2017-02-14 14:25:14 -05001127 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1128
1129 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1130 if (layer->fNext) {
1131 // need to punch a hole in the previous device, so we don't draw there, given that
1132 // the new top-layer will allow drawing to happen "below" it.
1133 SkRegion hole(ir);
1134 do {
1135 layer = layer->fNext;
1136 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1137 } while (layer->fNext);
1138 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001139}
1140
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001141int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001142 if (0xFF == alpha) {
1143 return this->saveLayer(bounds, nullptr);
1144 } else {
1145 SkPaint tmpPaint;
1146 tmpPaint.setAlpha(alpha);
1147 return this->saveLayer(bounds, &tmpPaint);
1148 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001149}
1150
Mike Reed148b7fd2018-12-18 17:38:18 -05001151void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1152 SkIRect devBounds;
1153 if (localBounds) {
1154 SkRect tmp;
1155 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1156 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1157 devBounds.setEmpty();
1158 }
1159 } else {
1160 devBounds = this->getDeviceClipBounds();
1161 }
1162 if (devBounds.isEmpty()) {
1163 return;
1164 }
1165
1166 SkBaseDevice* device = this->getTopDevice();
1167 if (nullptr == device) { // Do we still need this check???
1168 return;
1169 }
1170
1171 // need the bounds relative to the device itself
1172 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1173
1174 auto backImage = device->snapBackImage(devBounds);
1175 if (!backImage) {
1176 return;
1177 }
1178
1179 // we really need the save, so we can wack the fMCRec
1180 this->checkForDeferredSave();
1181
1182 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1183
1184 SkPaint paint;
1185 paint.setBlendMode(SkBlendMode::kClear);
Mike Reed9adc82c2019-04-23 10:28:13 -04001186 this->drawClippedToSaveBehind(paint);
Mike Reed148b7fd2018-12-18 17:38:18 -05001187}
1188
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189void SkCanvas::internalRestore() {
1190 SkASSERT(fMCStack.count() != 0);
1191
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001192 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001193 DeviceCM* layer = fMCRec->fLayer; // may be null
1194 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001195 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196
Mike Reed148b7fd2018-12-18 17:38:18 -05001197 // move this out before we do the actual restore
1198 auto backImage = std::move(fMCRec->fBackImage);
1199
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200 // now do the normal restore()
1201 fMCRec->~MCRec(); // balanced in save()
1202 fMCStack.pop_back();
1203 fMCRec = (MCRec*)fMCStack.back();
1204
Mike Reedc42a1cd2017-02-14 14:25:14 -05001205 if (fMCRec) {
1206 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1207 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001208
Mike Reed148b7fd2018-12-18 17:38:18 -05001209 if (backImage) {
1210 SkPaint paint;
1211 paint.setBlendMode(SkBlendMode::kDstOver);
1212 const int x = backImage->fLoc.x();
1213 const int y = backImage->fLoc.y();
1214 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1215 nullptr, SkMatrix::I());
1216 }
1217
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1219 since if we're being recorded, we don't want to record this (the
1220 recorder will have already recorded the restore).
1221 */
bsalomon49f085d2014-09-05 13:34:00 -07001222 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001223 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001224 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001225 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001226 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001227 layer->fPaint.get(),
1228 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001229 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001230 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001231 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001232 delete layer;
reedb679ca82015-04-07 04:40:48 -07001233 } else {
1234 // we're at the root
reeda499f902015-05-01 09:34:31 -07001235 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001236 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001237 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001239 }
msarettfbfa2582016-08-12 08:29:08 -07001240
1241 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001242 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001243 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1244 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245}
1246
reede8f30622016-03-23 18:59:25 -07001247sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001248 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001249 props = &fProps;
1250 }
1251 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001252}
1253
reede8f30622016-03-23 18:59:25 -07001254sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001255 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001256 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001257}
1258
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001259SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001260 return this->onImageInfo();
1261}
1262
1263SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001264 SkBaseDevice* dev = this->getDevice();
1265 if (dev) {
1266 return dev->imageInfo();
1267 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001268 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001269 }
1270}
1271
brianosman898235c2016-04-06 07:38:23 -07001272bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001273 return this->onGetProps(props);
1274}
1275
1276bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001277 SkBaseDevice* dev = this->getDevice();
1278 if (dev) {
1279 if (props) {
1280 *props = fProps;
1281 }
1282 return true;
1283 } else {
1284 return false;
1285 }
1286}
1287
reed6ceeebd2016-03-09 14:26:26 -08001288bool SkCanvas::peekPixels(SkPixmap* pmap) {
1289 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001290}
1291
reed884e97c2015-05-26 11:31:54 -07001292bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001293 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001294 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001295}
1296
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001297void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001298 SkPixmap pmap;
1299 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001300 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001301 }
1302 if (info) {
1303 *info = pmap.info();
1304 }
1305 if (rowBytes) {
1306 *rowBytes = pmap.rowBytes();
1307 }
1308 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001309 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001310 }
reed884e97c2015-05-26 11:31:54 -07001311 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001312}
1313
reed884e97c2015-05-26 11:31:54 -07001314bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001315 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001316 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001317}
1318
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320
Mike Reed8bcd1282019-03-13 16:51:54 -04001321// In our current design/features, we should never have a layer (src) in a different colorspace
1322// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1323// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1324// colorspace.
1325static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1326 SkASSERT(src == dst);
1327}
1328
Florin Malita53f77bd2017-04-28 13:48:37 -04001329void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1330 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001331 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001332 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333 paint = &tmp;
1334 }
reed@google.com4b226022011-01-11 18:32:13 +00001335
Ben Wagner2c312c42018-06-27 14:46:46 -04001336 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001337
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001339 SkBaseDevice* dstDev = iter.fDevice;
Mike Reed8bcd1282019-03-13 16:51:54 -04001340 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1341 srcDev->imageInfo().colorSpace());
reed@google.com76dd2772012-01-05 21:15:07 +00001342 paint = &looper.paint();
1343 SkImageFilter* filter = paint->getImageFilter();
1344 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001345 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001346 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1347 if (specialImage) {
Mike Reed8bcd1282019-03-13 16:51:54 -04001348 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1349 specialImage->getColorSpace());
Florin Malita53f77bd2017-04-28 13:48:37 -04001350 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1351 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001352 }
reed@google.com76dd2772012-01-05 21:15:07 +00001353 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001354 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001355 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356 }
reeda2217ef2016-07-20 06:04:34 -07001357
reed@google.com4e2b3d32011-04-07 14:18:59 +00001358 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001359}
1360
reed32704672015-12-16 08:27:10 -08001361/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001362
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001363void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001364 if (dx || dy) {
1365 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001366 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001367
reedfe69b502016-09-12 06:31:48 -07001368 // Translate shouldn't affect the is-scale-translateness of the matrix.
1369 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001370
Mike Reedc42a1cd2017-02-14 14:25:14 -05001371 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001372
reedfe69b502016-09-12 06:31:48 -07001373 this->didTranslate(dx,dy);
1374 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001375}
1376
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001377void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001378 SkMatrix m;
1379 m.setScale(sx, sy);
1380 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381}
1382
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001383void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001384 SkMatrix m;
1385 m.setRotate(degrees);
1386 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001387}
1388
bungeman7438bfc2016-07-12 15:01:19 -07001389void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1390 SkMatrix m;
1391 m.setRotate(degrees, px, py);
1392 this->concat(m);
1393}
1394
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001395void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001396 SkMatrix m;
1397 m.setSkew(sx, sy);
1398 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001399}
1400
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001401void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001402 if (matrix.isIdentity()) {
1403 return;
1404 }
1405
reed2ff1fce2014-12-11 07:07:37 -08001406 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001407 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001408 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001409
Mike Reed7627fa52017-02-08 10:07:53 -05001410 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001411
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001412 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001413}
1414
reed8c30a812016-04-20 16:36:51 -07001415void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001416 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001417 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001418
Mike Reedc42a1cd2017-02-14 14:25:14 -05001419 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001420}
1421
1422void SkCanvas::setMatrix(const SkMatrix& matrix) {
1423 this->checkForDeferredSave();
1424 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001425 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426}
1427
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001429 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430}
1431
1432//////////////////////////////////////////////////////////////////////////////
1433
Mike Reedc1f77742016-12-09 09:00:50 -05001434void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001435 if (!rect.isFinite()) {
1436 return;
1437 }
reed2ff1fce2014-12-11 07:07:37 -08001438 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001439 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1440 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001441}
1442
Mike Reedc1f77742016-12-09 09:00:50 -05001443void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001444 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001445
Mike Reed7627fa52017-02-08 10:07:53 -05001446 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001447
reedc64eff52015-11-21 12:39:45 -08001448 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001449 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1450 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001451 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452}
1453
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001454void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1455 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001456 if (fClipRestrictionRect.isEmpty()) {
1457 // we notify the device, but we *dont* resolve deferred saves (since we're just
1458 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001459 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001460 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001461 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001462 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001463 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001464 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001465 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1466 }
1467}
1468
Mike Reedc1f77742016-12-09 09:00:50 -05001469void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001470 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001471 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001472 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001473 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1474 } else {
1475 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001476 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001477}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001478
Mike Reedc1f77742016-12-09 09:00:50 -05001479void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001480 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001481
Brian Salomona3b45d42016-10-03 11:36:16 -04001482 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001483
Mike Reed7627fa52017-02-08 10:07:53 -05001484 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001485
Mike Reed20800c82017-11-15 16:09:04 -05001486 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1487 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001488 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001489}
1490
Mike Reedc1f77742016-12-09 09:00:50 -05001491void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001492 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001493 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001494
1495 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1496 SkRect r;
1497 if (path.isRect(&r)) {
1498 this->onClipRect(r, op, edgeStyle);
1499 return;
1500 }
1501 SkRRect rrect;
1502 if (path.isOval(&r)) {
1503 rrect.setOval(r);
1504 this->onClipRRect(rrect, op, edgeStyle);
1505 return;
1506 }
1507 if (path.isRRect(&rrect)) {
1508 this->onClipRRect(rrect, op, edgeStyle);
1509 return;
1510 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001511 }
robertphillips39f05382015-11-24 09:30:12 -08001512
1513 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001514}
1515
Mike Reedc1f77742016-12-09 09:00:50 -05001516void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001517 AutoValidateClip avc(this);
1518
Brian Salomona3b45d42016-10-03 11:36:16 -04001519 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001520
Mike Reed7627fa52017-02-08 10:07:53 -05001521 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001522
Brian Salomona3b45d42016-10-03 11:36:16 -04001523 const SkPath* rasterClipPath = &path;
1524 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001525 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1526 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001527 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001528}
1529
Mike Reedc1f77742016-12-09 09:00:50 -05001530void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001531 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001532 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001533}
1534
Mike Reedc1f77742016-12-09 09:00:50 -05001535void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001536 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001537
reed@google.com5c3d1472011-02-22 19:12:23 +00001538 AutoValidateClip avc(this);
1539
Mike Reed20800c82017-11-15 16:09:04 -05001540 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001541 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001542}
1543
reed@google.com819c9212011-02-23 18:56:55 +00001544#ifdef SK_DEBUG
1545void SkCanvas::validateClip() const {
1546 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001547 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001548 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001549 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001550 return;
1551 }
reed@google.com819c9212011-02-23 18:56:55 +00001552}
1553#endif
1554
Mike Reeda1361362017-03-07 09:37:29 -05001555bool SkCanvas::androidFramework_isClipAA() const {
1556 bool containsAA = false;
1557
1558 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1559
1560 return containsAA;
1561}
1562
1563class RgnAccumulator {
1564 SkRegion* fRgn;
1565public:
1566 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1567 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1568 SkIPoint origin = device->getOrigin();
1569 if (origin.x() | origin.y()) {
1570 rgn->translate(origin.x(), origin.y());
1571 }
1572 fRgn->op(*rgn, SkRegion::kUnion_Op);
1573 }
1574};
1575
1576void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1577 RgnAccumulator accum(rgn);
1578 SkRegion tmp;
1579
1580 rgn->setEmpty();
1581 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001582}
1583
reed@google.com5c3d1472011-02-22 19:12:23 +00001584///////////////////////////////////////////////////////////////////////////////
1585
reed@google.com754de5f2014-02-24 19:38:20 +00001586bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001587 return fMCRec->fRasterClip.isEmpty();
1588
1589 // TODO: should we only use the conservative answer in a recording canvas?
1590#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001591 SkBaseDevice* dev = this->getTopDevice();
1592 // if no device we return true
1593 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001594#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001595}
1596
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001597bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001598 SkBaseDevice* dev = this->getTopDevice();
1599 // if no device we return false
1600 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001601}
1602
msarettfbfa2582016-08-12 08:29:08 -07001603static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1604#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1605 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1606 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1607 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1608 return 0xF != _mm_movemask_ps(mask);
1609#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1610 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1611 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1612 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1613 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1614#else
1615 SkRect devRectAsRect;
1616 SkRect devClipAsRect;
1617 devRect.store(&devRectAsRect.fLeft);
1618 devClip.store(&devClipAsRect.fLeft);
1619 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1620#endif
1621}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001622
msarettfbfa2582016-08-12 08:29:08 -07001623// It's important for this function to not be inlined. Otherwise the compiler will share code
1624// between the fast path and the slow path, resulting in two slow paths.
1625static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1626 const SkMatrix& matrix) {
1627 SkRect deviceRect;
1628 matrix.mapRect(&deviceRect, src);
1629 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1630}
1631
1632bool SkCanvas::quickReject(const SkRect& src) const {
1633#ifdef SK_DEBUG
1634 // Verify that fDeviceClipBounds are set properly.
1635 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001636 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001637 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001638 } else {
msarettfbfa2582016-08-12 08:29:08 -07001639 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001640 }
msarettfbfa2582016-08-12 08:29:08 -07001641
msarett9637ea92016-08-18 14:03:30 -07001642 // Verify that fIsScaleTranslate is set properly.
1643 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001644#endif
1645
msarett9637ea92016-08-18 14:03:30 -07001646 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001647 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1648 }
1649
1650 // We inline the implementation of mapScaleTranslate() for the fast path.
1651 float sx = fMCRec->fMatrix.getScaleX();
1652 float sy = fMCRec->fMatrix.getScaleY();
1653 float tx = fMCRec->fMatrix.getTranslateX();
1654 float ty = fMCRec->fMatrix.getTranslateY();
1655 Sk4f scale(sx, sy, sx, sy);
1656 Sk4f trans(tx, ty, tx, ty);
1657
1658 // Apply matrix.
1659 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1660
1661 // Make sure left < right, top < bottom.
1662 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1663 Sk4f min = Sk4f::Min(ltrb, rblt);
1664 Sk4f max = Sk4f::Max(ltrb, rblt);
1665 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1666 // ARM this sequence generates the fastest (a single instruction).
1667 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1668
1669 // Check if the device rect is NaN or outside the clip.
1670 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001671}
1672
reed@google.com3b3e8952012-08-16 20:53:31 +00001673bool SkCanvas::quickReject(const SkPath& path) const {
1674 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001675}
1676
Mike Klein83c8dd92017-11-28 17:08:45 -05001677SkRect SkCanvas::getLocalClipBounds() const {
1678 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001679 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001680 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681 }
1682
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001683 SkMatrix inverse;
1684 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001685 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001686 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001687 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001688
Mike Reed42e8c532017-01-23 14:09:13 -05001689 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001690 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001691 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001692
Mike Reedb57b9312018-04-23 12:12:54 -04001693 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001694 inverse.mapRect(&bounds, r);
1695 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001696}
1697
Mike Klein83c8dd92017-11-28 17:08:45 -05001698SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001699 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001700}
1701
reed@android.com8a1c16f2008-12-17 15:59:43 +00001702const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001703 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001704}
1705
Brian Osman11052242016-10-27 14:47:55 -04001706GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001707 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001708 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001709}
1710
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001711GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001712 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001713 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001714}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001715
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001716void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1717 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001718 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001719 if (outer.isEmpty()) {
1720 return;
1721 }
1722 if (inner.isEmpty()) {
1723 this->drawRRect(outer, paint);
1724 return;
1725 }
1726
1727 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001728 // be able to return ...
1729 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001730 //
1731 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001732 if (!outer.getBounds().contains(inner.getBounds())) {
1733 return;
1734 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001735
1736 this->onDrawDRRect(outer, inner, paint);
1737}
1738
reed41af9662015-01-05 07:49:08 -08001739void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001740 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001741 this->onDrawPaint(paint);
1742}
1743
1744void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001745 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001746 // To avoid redundant logic in our culling code and various backends, we always sort rects
1747 // before passing them along.
1748 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001749}
1750
Mike Reedd5674082019-04-19 15:00:47 -04001751void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1752 TRACE_EVENT0("skia", TRACE_FUNC);
1753 this->onDrawBehind(paint);
1754}
1755
msarettdca352e2016-08-26 06:37:45 -07001756void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001757 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001758 if (region.isEmpty()) {
1759 return;
1760 }
1761
1762 if (region.isRect()) {
1763 return this->drawIRect(region.getBounds(), paint);
1764 }
1765
1766 this->onDrawRegion(region, paint);
1767}
1768
reed41af9662015-01-05 07:49:08 -08001769void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001770 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001771 // To avoid redundant logic in our culling code and various backends, we always sort rects
1772 // before passing them along.
1773 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001774}
1775
1776void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001777 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001778 this->onDrawRRect(rrect, paint);
1779}
1780
1781void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001782 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001783 this->onDrawPoints(mode, count, pts, paint);
1784}
1785
Mike Reede88a1cb2017-03-17 09:50:46 -04001786void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1787 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001788 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001789 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001790 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1791 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001792 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001793}
1794
1795void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001796 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001797 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001798 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1799}
1800
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001801void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1802 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001803 TRACE_EVENT0("skia", TRACE_FUNC);
1804 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001805 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001806 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1807}
1808
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001809void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1810 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001811 TRACE_EVENT0("skia", TRACE_FUNC);
1812 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001813 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001814 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001815}
1816
1817void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001818 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001819 this->onDrawPath(path, paint);
1820}
1821
reeda85d4d02015-05-06 12:56:48 -07001822void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001823 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001824 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001825 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001826}
1827
Mike Reedc4e31092018-01-30 11:15:27 -05001828// Returns true if the rect can be "filled" : non-empty and finite
1829static bool fillable(const SkRect& r) {
1830 SkScalar w = r.width();
1831 SkScalar h = r.height();
1832 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1833}
1834
reede47829b2015-08-06 10:02:53 -07001835void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1836 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001837 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001838 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001839 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001840 return;
1841 }
1842 this->onDrawImageRect(image, &src, dst, paint, constraint);
1843}
reed41af9662015-01-05 07:49:08 -08001844
reed84984ef2015-07-17 07:09:43 -07001845void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1846 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001847 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001848 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001849}
1850
Brian Salomonf08002c2018-10-26 16:15:46 -04001851void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001852 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001853 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001854 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001855}
reede47829b2015-08-06 10:02:53 -07001856
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001857namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001858class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001859public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001860 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1861 if (!origPaint) {
1862 return;
1863 }
1864 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1865 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1866 }
1867 if (origPaint->getMaskFilter()) {
1868 fPaint.writable()->setMaskFilter(nullptr);
1869 }
1870 if (origPaint->isAntiAlias()) {
1871 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001872 }
1873 }
1874
1875 const SkPaint* get() const {
1876 return fPaint;
1877 }
1878
1879private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001880 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001881};
1882} // namespace
1883
reed4c21dc52015-06-25 12:32:03 -07001884void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1885 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001886 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001887 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001888 if (dst.isEmpty()) {
1889 return;
1890 }
msarett552bca92016-08-03 06:53:26 -07001891 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001892 LatticePaint latticePaint(paint);
1893 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001894 } else {
reede47829b2015-08-06 10:02:53 -07001895 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001896 }
reed4c21dc52015-06-25 12:32:03 -07001897}
1898
msarett16882062016-08-16 09:31:08 -07001899void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1900 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001901 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001902 RETURN_ON_NULL(image);
1903 if (dst.isEmpty()) {
1904 return;
1905 }
msarett71df2d72016-09-30 12:41:42 -07001906
1907 SkIRect bounds;
1908 Lattice latticePlusBounds = lattice;
1909 if (!latticePlusBounds.fBounds) {
1910 bounds = SkIRect::MakeWH(image->width(), image->height());
1911 latticePlusBounds.fBounds = &bounds;
1912 }
1913
1914 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001915 LatticePaint latticePaint(paint);
1916 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001917 } else {
1918 this->drawImageRect(image, dst, paint);
1919 }
1920}
1921
reed41af9662015-01-05 07:49:08 -08001922void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001923 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001924 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001925 return;
1926 }
reed41af9662015-01-05 07:49:08 -08001927 this->onDrawBitmap(bitmap, dx, dy, paint);
1928}
1929
reede47829b2015-08-06 10:02:53 -07001930void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001931 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001932 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001933 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001934 return;
1935 }
reede47829b2015-08-06 10:02:53 -07001936 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001937}
1938
reed84984ef2015-07-17 07:09:43 -07001939void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1940 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001941 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001942}
1943
reede47829b2015-08-06 10:02:53 -07001944void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1945 SrcRectConstraint constraint) {
1946 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1947 constraint);
1948}
reede47829b2015-08-06 10:02:53 -07001949
reed41af9662015-01-05 07:49:08 -08001950void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1951 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001952 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001953 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001954 return;
1955 }
msarett552bca92016-08-03 06:53:26 -07001956 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001957 LatticePaint latticePaint(paint);
1958 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001959 } else {
reeda5517e22015-07-14 10:54:12 -07001960 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001961 }
reed41af9662015-01-05 07:49:08 -08001962}
1963
msarettc573a402016-08-02 08:05:56 -07001964void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1965 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001966 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001967 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001968 return;
1969 }
msarett71df2d72016-09-30 12:41:42 -07001970
1971 SkIRect bounds;
1972 Lattice latticePlusBounds = lattice;
1973 if (!latticePlusBounds.fBounds) {
1974 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1975 latticePlusBounds.fBounds = &bounds;
1976 }
1977
1978 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001979 LatticePaint latticePaint(paint);
1980 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001981 } else {
msarett16882062016-08-16 09:31:08 -07001982 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001983 }
msarettc573a402016-08-02 08:05:56 -07001984}
1985
reed71c3c762015-06-24 10:29:17 -07001986void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001987 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001988 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001989 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001990 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001991 if (count <= 0) {
1992 return;
1993 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001994 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001995 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001996 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001997}
1998
reedf70b5312016-03-04 16:36:20 -08001999void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002000 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08002001 if (key) {
2002 this->onDrawAnnotation(rect, key, value);
2003 }
2004}
2005
reede47829b2015-08-06 10:02:53 -07002006void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2007 const SkPaint* paint, SrcRectConstraint constraint) {
2008 if (src) {
2009 this->drawImageRect(image, *src, dst, paint, constraint);
2010 } else {
2011 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2012 dst, paint, constraint);
2013 }
2014}
2015void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2016 const SkPaint* paint, SrcRectConstraint constraint) {
2017 if (src) {
2018 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2019 } else {
2020 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2021 dst, paint, constraint);
2022 }
2023}
2024
Mike Reed4204da22017-05-17 08:53:36 -04002025void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002026 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04002027 this->onDrawShadowRec(path, rec);
2028}
2029
2030void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
2031 SkPaint paint;
2032 const SkRect& pathBounds = path.getBounds();
2033
Ben Wagner2c312c42018-06-27 14:46:46 -04002034 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04002035 while (iter.next()) {
2036 iter.fDevice->drawShadow(path, rec);
2037 }
2038 LOOPER_END
2039}
2040
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002041void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2042 QuadAAFlags aaFlags, SkColor color, SkBlendMode mode) {
2043 TRACE_EVENT0("skia", TRACE_FUNC);
2044 // Make sure the rect is sorted before passing it along
2045 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2046}
2047
2048void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2049 const SkPoint dstClips[],
2050 const SkMatrix preViewMatrices[],
2051 const SkPaint* paint,
2052 SrcRectConstraint constraint) {
2053 TRACE_EVENT0("skia", TRACE_FUNC);
2054 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2055}
2056
reed@android.com8a1c16f2008-12-17 15:59:43 +00002057//////////////////////////////////////////////////////////////////////////////
2058// These are the virtual drawing methods
2059//////////////////////////////////////////////////////////////////////////////
2060
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002061void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002062 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002063 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2064 }
2065}
2066
reed41af9662015-01-05 07:49:08 -08002067void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002068 this->internalDrawPaint(paint);
2069}
2070
2071void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002072 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002073
2074 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002075 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002076 }
2077
reed@google.com4e2b3d32011-04-07 14:18:59 +00002078 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002079}
2080
reed41af9662015-01-05 07:49:08 -08002081void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2082 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002083 if ((long)count <= 0) {
2084 return;
2085 }
2086
Mike Reed822128b2017-02-28 16:41:03 -05002087 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002088 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002089 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002090 // special-case 2 points (common for drawing a single line)
2091 if (2 == count) {
2092 r.set(pts[0], pts[1]);
2093 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002094 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002095 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002096 if (!r.isFinite()) {
2097 return;
2098 }
Mike Reed822128b2017-02-28 16:41:03 -05002099 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002100 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2101 return;
2102 }
2103 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002104 }
reed@google.coma584aed2012-05-16 14:06:02 +00002105
halcanary96fcdcc2015-08-27 07:41:13 -07002106 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002107
Ben Wagner2c312c42018-06-27 14:46:46 -04002108 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002109
reed@android.com8a1c16f2008-12-17 15:59:43 +00002110 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002111 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002112 }
reed@google.com4b226022011-01-11 18:32:13 +00002113
reed@google.com4e2b3d32011-04-07 14:18:59 +00002114 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002115}
2116
reed4a167172016-08-18 17:15:25 -07002117static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2118 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07002119 (intptr_t)paint.getLooper() ) != 0;
2120}
2121
reed41af9662015-01-05 07:49:08 -08002122void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002123 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002124 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002125 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002126 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002127 return;
2128 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002129 }
reed@google.com4b226022011-01-11 18:32:13 +00002130
reed4a167172016-08-18 17:15:25 -07002131 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002132 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002133
reed4a167172016-08-18 17:15:25 -07002134 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002135 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002136 }
2137
2138 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002139 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002140 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002141 SkDrawIter iter(this);
2142 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002143 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002144 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002146}
2147
msarett44df6512016-08-25 13:54:30 -07002148void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002149 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002150 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002151 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002152 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2153 return;
2154 }
msarett44df6512016-08-25 13:54:30 -07002155 }
2156
Ben Wagner2c312c42018-06-27 14:46:46 -04002157 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002158
2159 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002160 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002161 }
2162
2163 LOOPER_END
2164}
2165
Mike Reedd5674082019-04-19 15:00:47 -04002166void SkCanvas::onDrawBehind(const SkPaint& paint) {
2167 SkIRect bounds;
2168 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2169 for (;;) {
2170 const MCRec* rec = (const MCRec*)iter.prev();
2171 if (!rec) {
2172 return; // no backimages, so nothing to draw
2173 }
2174 if (rec->fBackImage) {
2175 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2176 rec->fBackImage->fImage->width(),
2177 rec->fBackImage->fImage->height());
2178 break;
2179 }
2180 }
2181
2182 LOOPER_BEGIN(paint, nullptr)
2183
2184 while (iter.next()) {
2185 SkBaseDevice* dev = iter.fDevice;
2186
Mike Reedd5674082019-04-19 15:00:47 -04002187 dev->save();
2188 // We use clipRegion because it is already defined to operate in dev-space
2189 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2190 // but we don't want that, so we undo that before calling in.
2191 SkRegion rgn(bounds.makeOffset(dev->fOrigin.fX, dev->fOrigin.fY));
2192 dev->clipRegion(rgn, SkClipOp::kIntersect);
2193 dev->drawPaint(looper.paint());
Mike Reed9adc82c2019-04-23 10:28:13 -04002194 dev->restore(fMCRec->fMatrix);
Mike Reedd5674082019-04-19 15:00:47 -04002195 }
2196
2197 LOOPER_END
2198}
2199
reed41af9662015-01-05 07:49:08 -08002200void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002201 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002202 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002203 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002204 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002205 return;
2206 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002207 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002208
Ben Wagner2c312c42018-06-27 14:46:46 -04002209 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002210
2211 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002212 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002213 }
2214
2215 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002216}
2217
bsalomonac3aa242016-08-19 11:25:19 -07002218void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2219 SkScalar sweepAngle, bool useCenter,
2220 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002221 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002222 if (paint.canComputeFastBounds()) {
2223 SkRect storage;
2224 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002225 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002226 return;
2227 }
bsalomonac3aa242016-08-19 11:25:19 -07002228 }
2229
Ben Wagner2c312c42018-06-27 14:46:46 -04002230 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002231
2232 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002233 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002234 }
2235
2236 LOOPER_END
2237}
2238
reed41af9662015-01-05 07:49:08 -08002239void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002240 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002241 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002242 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2243 return;
2244 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002245 }
2246
2247 if (rrect.isRect()) {
2248 // call the non-virtual version
2249 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002250 return;
2251 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002252 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002253 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2254 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002255 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002256
Ben Wagner2c312c42018-06-27 14:46:46 -04002257 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002258
2259 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002260 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002261 }
2262
2263 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002264}
2265
Mike Reed822128b2017-02-28 16:41:03 -05002266void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002267 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002268 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002269 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2270 return;
2271 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002272 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002273
Ben Wagner2c312c42018-06-27 14:46:46 -04002274 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002275
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002276 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002277 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002278 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002279
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002280 LOOPER_END
2281}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002282
reed41af9662015-01-05 07:49:08 -08002283void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002284 if (!path.isFinite()) {
2285 return;
2286 }
2287
Mike Reed822128b2017-02-28 16:41:03 -05002288 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002289 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002290 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002291 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2292 return;
2293 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002294 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002295
Mike Reed822128b2017-02-28 16:41:03 -05002296 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002297 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002298 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002299 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002300 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002301 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302
Ben Wagner2c312c42018-06-27 14:46:46 -04002303 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002304
2305 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002306 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 }
2308
reed@google.com4e2b3d32011-04-07 14:18:59 +00002309 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002310}
2311
reed262a71b2015-12-05 13:07:27 -08002312bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002313 if (!paint.getImageFilter()) {
2314 return false;
2315 }
2316
2317 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002318 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002319 return false;
2320 }
2321
2322 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2323 // Once we can filter and the filter will return a result larger than itself, we should be
2324 // able to remove this constraint.
2325 // skbug.com/4526
2326 //
2327 SkPoint pt;
2328 ctm.mapXY(x, y, &pt);
2329 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2330 return ir.contains(fMCRec->fRasterClip.getBounds());
2331}
2332
Mike Reedf441cfc2018-04-11 14:50:16 -04002333// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2334// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2335// null.
2336static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2337 if (paintParam) {
2338 *real = *paintParam;
2339 real->setStyle(SkPaint::kFill_Style);
2340 real->setPathEffect(nullptr);
2341 paintParam = real;
2342 }
2343 return paintParam;
2344}
2345
reeda85d4d02015-05-06 12:56:48 -07002346void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002347 SkPaint realPaint;
2348 paint = init_image_paint(&realPaint, paint);
2349
reeda85d4d02015-05-06 12:56:48 -07002350 SkRect bounds = SkRect::MakeXYWH(x, y,
2351 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002352 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002353 SkRect tmp = bounds;
2354 if (paint) {
2355 paint->computeFastBounds(tmp, &tmp);
2356 }
2357 if (this->quickReject(tmp)) {
2358 return;
2359 }
reeda85d4d02015-05-06 12:56:48 -07002360 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002361 // At this point we need a real paint object. If the caller passed null, then we should
2362 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2363 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2364 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002365
reeda2217ef2016-07-20 06:04:34 -07002366 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002367 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2368 *paint);
2369 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002370 special = this->getDevice()->makeSpecial(image);
2371 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002372 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002373 }
2374 }
2375
reed262a71b2015-12-05 13:07:27 -08002376 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2377
reeda85d4d02015-05-06 12:56:48 -07002378 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002379 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002380 if (special) {
2381 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002382 iter.fDevice->ctm().mapXY(x, y, &pt);
2383 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002384 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002385 SkScalarRoundToInt(pt.fY), pnt,
2386 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002387 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002388 iter.fDevice->drawImageRect(
2389 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2390 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002391 }
reeda85d4d02015-05-06 12:56:48 -07002392 }
halcanary9d524f22016-03-29 09:03:52 -07002393
reeda85d4d02015-05-06 12:56:48 -07002394 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002395}
2396
reed41af9662015-01-05 07:49:08 -08002397void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002398 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002399 SkPaint realPaint;
2400 paint = init_image_paint(&realPaint, paint);
2401
halcanary96fcdcc2015-08-27 07:41:13 -07002402 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002403 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002404 if (paint) {
2405 paint->computeFastBounds(dst, &storage);
2406 }
2407 if (this->quickReject(storage)) {
2408 return;
2409 }
reeda85d4d02015-05-06 12:56:48 -07002410 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002411 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002412
Ben Wagner2c312c42018-06-27 14:46:46 -04002413 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002414
reeda85d4d02015-05-06 12:56:48 -07002415 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002416 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002417 }
halcanary9d524f22016-03-29 09:03:52 -07002418
reeda85d4d02015-05-06 12:56:48 -07002419 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002420}
2421
reed41af9662015-01-05 07:49:08 -08002422void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002423 SkDEBUGCODE(bitmap.validate();)
2424
reed33366972015-10-08 09:22:02 -07002425 if (bitmap.drawsNothing()) {
2426 return;
2427 }
2428
Mike Reedf441cfc2018-04-11 14:50:16 -04002429 SkPaint realPaint;
2430 init_image_paint(&realPaint, paint);
2431 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002432
Mike Reed822128b2017-02-28 16:41:03 -05002433 SkRect bounds;
2434 bitmap.getBounds(&bounds);
2435 bounds.offset(x, y);
2436 bool canFastBounds = paint->canComputeFastBounds();
2437 if (canFastBounds) {
2438 SkRect storage;
2439 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002440 return;
2441 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002442 }
reed@google.com4b226022011-01-11 18:32:13 +00002443
reeda2217ef2016-07-20 06:04:34 -07002444 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002445 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2446 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002447 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002448 special = this->getDevice()->makeSpecial(bitmap);
2449 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002450 drawAsSprite = false;
2451 }
2452 }
2453
Mike Reed822128b2017-02-28 16:41:03 -05002454 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002455
2456 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002457 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002458 if (special) {
reed262a71b2015-12-05 13:07:27 -08002459 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002460 iter.fDevice->ctm().mapXY(x, y, &pt);
2461 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002462 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002463 SkScalarRoundToInt(pt.fY), pnt,
2464 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002465 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002466 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2467 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2468 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002469 }
reed33366972015-10-08 09:22:02 -07002470 }
msarettfbfa2582016-08-12 08:29:08 -07002471
reed33366972015-10-08 09:22:02 -07002472 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473}
2474
reed@google.com9987ec32011-09-07 11:57:52 +00002475// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002476void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002477 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002478 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002479 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480 return;
2481 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002482
halcanary96fcdcc2015-08-27 07:41:13 -07002483 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002484 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002485 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2486 return;
2487 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488 }
reed@google.com3d608122011-11-21 15:16:16 +00002489
reed@google.com33535f32012-09-25 15:37:50 +00002490 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002491 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002492 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002493 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002494
Ben Wagner2c312c42018-06-27 14:46:46 -04002495 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002496
reed@google.com33535f32012-09-25 15:37:50 +00002497 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002498 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002499 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002500
reed@google.com33535f32012-09-25 15:37:50 +00002501 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002502}
2503
reed41af9662015-01-05 07:49:08 -08002504void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002505 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002506 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002507 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002508}
2509
reed4c21dc52015-06-25 12:32:03 -07002510void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2511 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002512 SkPaint realPaint;
2513 paint = init_image_paint(&realPaint, paint);
2514
halcanary96fcdcc2015-08-27 07:41:13 -07002515 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002516 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002517 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2518 return;
2519 }
reed@google.com3d608122011-11-21 15:16:16 +00002520 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002521 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002522
Ben Wagner2c312c42018-06-27 14:46:46 -04002523 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002524
reed4c21dc52015-06-25 12:32:03 -07002525 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002526 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002527 }
halcanary9d524f22016-03-29 09:03:52 -07002528
reed4c21dc52015-06-25 12:32:03 -07002529 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002530}
2531
reed41af9662015-01-05 07:49:08 -08002532void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2533 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002534 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002535 SkPaint realPaint;
2536 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002537
halcanary96fcdcc2015-08-27 07:41:13 -07002538 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002539 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002540 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2541 return;
2542 }
reed4c21dc52015-06-25 12:32:03 -07002543 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002544 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002545
Ben Wagner2c312c42018-06-27 14:46:46 -04002546 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002547
reed4c21dc52015-06-25 12:32:03 -07002548 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002549 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002550 }
halcanary9d524f22016-03-29 09:03:52 -07002551
reed4c21dc52015-06-25 12:32:03 -07002552 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002553}
2554
msarett16882062016-08-16 09:31:08 -07002555void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2556 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002557 SkPaint realPaint;
2558 paint = init_image_paint(&realPaint, paint);
2559
msarett16882062016-08-16 09:31:08 -07002560 if (nullptr == paint || paint->canComputeFastBounds()) {
2561 SkRect storage;
2562 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2563 return;
2564 }
2565 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002566 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002567
Ben Wagner2c312c42018-06-27 14:46:46 -04002568 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002569
2570 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002571 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002572 }
2573
2574 LOOPER_END
2575}
2576
2577void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2578 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002579 SkPaint realPaint;
2580 paint = init_image_paint(&realPaint, paint);
2581
msarett16882062016-08-16 09:31:08 -07002582 if (nullptr == paint || paint->canComputeFastBounds()) {
2583 SkRect storage;
2584 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2585 return;
2586 }
2587 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002588 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002589
Ben Wagner2c312c42018-06-27 14:46:46 -04002590 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002591
2592 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002593 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002594 }
2595
2596 LOOPER_END
2597}
2598
fmalita00d5c2c2014-08-21 08:53:26 -07002599void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2600 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002601 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002602 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002603 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002604 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002605 SkRect tmp;
2606 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2607 return;
2608 }
2609 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002610 }
2611
fmalita024f9962015-03-03 19:08:17 -08002612 // We cannot filter in the looper as we normally do, because the paint is
2613 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002614 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002615
fmalitaaa1b9122014-08-28 14:32:24 -07002616 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002617 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002618 }
2619
fmalitaaa1b9122014-08-28 14:32:24 -07002620 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002621}
2622
Mike Reed358fcad2018-11-23 15:27:51 -05002623// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002624void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002625 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2626 TRACE_EVENT0("skia", TRACE_FUNC);
2627 if (byteLength) {
2628 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002629 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002630 }
2631}
Mike Reed4f81bb72019-01-23 09:23:00 -05002632
fmalita00d5c2c2014-08-21 08:53:26 -07002633void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2634 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002635 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002636 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002637 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002638 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002639}
reed@google.come0d9ce82014-04-23 04:00:17 +00002640
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002641void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002642 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002643 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002644
2645 while (iter.next()) {
2646 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002647 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002648 }
2649
2650 LOOPER_END
2651}
2652
dandovb3c9d1c2014-08-12 08:34:29 -07002653void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002654 const SkPoint texCoords[4], SkBlendMode bmode,
2655 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002656 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002657 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002658 return;
2659 }
mtklein6cfa73a2014-08-13 13:33:49 -07002660
Mike Reedfaba3712016-11-03 14:45:31 -04002661 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002662}
2663
2664void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002665 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002666 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002667 // Since a patch is always within the convex hull of the control points, we discard it when its
2668 // bounding rectangle is completely outside the current clip.
2669 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002670 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002671 if (this->quickReject(bounds)) {
2672 return;
2673 }
mtklein6cfa73a2014-08-13 13:33:49 -07002674
Ben Wagner2c312c42018-06-27 14:46:46 -04002675 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002676
dandovecfff212014-08-04 10:02:00 -07002677 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002678 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002679 }
mtklein6cfa73a2014-08-13 13:33:49 -07002680
dandovecfff212014-08-04 10:02:00 -07002681 LOOPER_END
2682}
2683
reeda8db7282015-07-07 10:22:31 -07002684void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002685#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002686 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002687#endif
reede3b38ce2016-01-08 09:18:44 -08002688 RETURN_ON_NULL(dr);
2689 if (x || y) {
2690 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2691 this->onDrawDrawable(dr, &matrix);
2692 } else {
2693 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002694 }
2695}
2696
reeda8db7282015-07-07 10:22:31 -07002697void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002698#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002699 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002700#endif
reede3b38ce2016-01-08 09:18:44 -08002701 RETURN_ON_NULL(dr);
2702 if (matrix && matrix->isIdentity()) {
2703 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002704 }
reede3b38ce2016-01-08 09:18:44 -08002705 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002706}
2707
2708void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002709 // drawable bounds are no longer reliable (e.g. android displaylist)
2710 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002711 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002712}
2713
reed71c3c762015-06-24 10:29:17 -07002714void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002715 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002716 const SkRect* cull, const SkPaint* paint) {
2717 if (cull && this->quickReject(*cull)) {
2718 return;
2719 }
2720
2721 SkPaint pnt;
2722 if (paint) {
2723 pnt = *paint;
2724 }
halcanary9d524f22016-03-29 09:03:52 -07002725
Ben Wagner2c312c42018-06-27 14:46:46 -04002726 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002727 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002728 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002729 }
2730 LOOPER_END
2731}
2732
reedf70b5312016-03-04 16:36:20 -08002733void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2734 SkASSERT(key);
2735
2736 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002737 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002738 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002739 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002740 }
2741 LOOPER_END
2742}
2743
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002744void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2745 SkColor color, SkBlendMode mode) {
2746 SkASSERT(r.isSorted());
2747
2748 // If this used a paint, it would be a filled color with blend mode, which does not
2749 // need to use an autodraw loop, so use SkDrawIter directly.
2750 if (this->quickReject(r)) {
2751 return;
2752 }
2753
2754 this->predrawNotify();
2755 SkDrawIter iter(this);
2756 while(iter.next()) {
2757 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2758 }
2759}
2760
2761void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2762 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2763 const SkPaint* paint, SrcRectConstraint constraint) {
2764 SkPaint realPaint;
2765 init_image_paint(&realPaint, paint);
2766
2767 // Looper is used when there are image filters, which drawEdgeAAImageSet needs to support
2768 // for Chromium's RenderPassDrawQuads' filters.
2769 LOOPER_BEGIN(realPaint, nullptr)
2770 while (iter.next()) {
2771 iter.fDevice->drawEdgeAAImageSet(
2772 imageSet, count, dstClips, preViewMatrices, looper.paint(), constraint);
2773 }
2774 LOOPER_END
2775}
2776
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777//////////////////////////////////////////////////////////////////////////////
2778// These methods are NOT virtual, and therefore must call back into virtual
2779// methods, rather than actually drawing themselves.
2780//////////////////////////////////////////////////////////////////////////////
2781
reed374772b2016-10-05 17:33:02 -07002782void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002785 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 this->drawPaint(paint);
2787}
2788
2789void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002790 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2792}
2793
Mike Reed3661bc92017-02-22 13:21:42 -05002794void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796 pts[0].set(x0, y0);
2797 pts[1].set(x1, y1);
2798 this->drawPoints(kLines_PointMode, 2, pts, paint);
2799}
2800
Mike Reed3661bc92017-02-22 13:21:42 -05002801void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002802 if (radius < 0) {
2803 radius = 0;
2804 }
2805
2806 SkRect r;
2807 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002808 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809}
2810
2811void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2812 const SkPaint& paint) {
2813 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002814 SkRRect rrect;
2815 rrect.setRectXY(r, rx, ry);
2816 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817 } else {
2818 this->drawRect(r, paint);
2819 }
2820}
2821
reed@android.com8a1c16f2008-12-17 15:59:43 +00002822void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2823 SkScalar sweepAngle, bool useCenter,
2824 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002825 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002826 if (oval.isEmpty() || !sweepAngle) {
2827 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828 }
bsalomon21af9ca2016-08-25 12:29:23 -07002829 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830}
2831
reed@android.comf76bacf2009-05-13 14:00:33 +00002832///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002833#ifdef SK_DISABLE_SKPICTURE
2834void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002835
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002836
2837void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2838 const SkPaint* paint) {}
2839#else
Mike Klein88d90712018-01-27 17:30:04 +00002840/**
2841 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2842 * against the playback cost of recursing into the subpicture to get at its actual ops.
2843 *
2844 * For now we pick a conservatively small value, though measurement (and other heuristics like
2845 * the type of ops contained) may justify changing this value.
2846 */
2847#define kMaxPictureOpsToUnrollInsteadOfRef 1
2848
reedd5fa1a42014-08-09 11:08:05 -07002849void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002850 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002851 RETURN_ON_NULL(picture);
2852
reede3b38ce2016-01-08 09:18:44 -08002853 if (matrix && matrix->isIdentity()) {
2854 matrix = nullptr;
2855 }
Mike Klein88d90712018-01-27 17:30:04 +00002856 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2857 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2858 picture->playback(this);
2859 } else {
2860 this->onDrawPicture(picture, matrix, paint);
2861 }
reedd5fa1a42014-08-09 11:08:05 -07002862}
robertphillips9b14f262014-06-04 05:40:44 -07002863
reedd5fa1a42014-08-09 11:08:05 -07002864void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2865 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002866 if (!paint || paint->canComputeFastBounds()) {
2867 SkRect bounds = picture->cullRect();
2868 if (paint) {
2869 paint->computeFastBounds(bounds, &bounds);
2870 }
2871 if (matrix) {
2872 matrix->mapRect(&bounds);
2873 }
2874 if (this->quickReject(bounds)) {
2875 return;
2876 }
2877 }
2878
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002879 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002880 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002881}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002882#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002883
reed@android.com8a1c16f2008-12-17 15:59:43 +00002884///////////////////////////////////////////////////////////////////////////////
2885///////////////////////////////////////////////////////////////////////////////
2886
reed3aafe112016-08-18 12:45:34 -07002887SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002888 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002889
2890 SkASSERT(canvas);
2891
reed3aafe112016-08-18 12:45:34 -07002892 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002893 fDone = !fImpl->next();
2894}
2895
2896SkCanvas::LayerIter::~LayerIter() {
2897 fImpl->~SkDrawIter();
2898}
2899
2900void SkCanvas::LayerIter::next() {
2901 fDone = !fImpl->next();
2902}
2903
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002904SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002905 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002906}
2907
2908const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002909 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002910}
2911
2912const SkPaint& SkCanvas::LayerIter::paint() const {
2913 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002914 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002915 paint = &fDefaultPaint;
2916 }
2917 return *paint;
2918}
2919
Mike Reedca37f322018-03-08 13:22:16 -05002920SkIRect SkCanvas::LayerIter::clipBounds() const {
2921 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002922}
2923
reed@android.com8a1c16f2008-12-17 15:59:43 +00002924int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2925int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002926
2927///////////////////////////////////////////////////////////////////////////////
2928
Brian Osmane8a98632019-04-10 10:26:10 -04002929SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2930SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2931SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2932SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2933
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002934SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2935 const SkRect& dstRect, int matrixIndex, float alpha,
2936 unsigned aaFlags, bool hasClip)
2937 : fImage(std::move(image))
2938 , fSrcRect(srcRect)
2939 , fDstRect(dstRect)
2940 , fMatrixIndex(matrixIndex)
2941 , fAlpha(alpha)
2942 , fAAFlags(aaFlags)
2943 , fHasClip(hasClip) {}
2944
2945SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2946 const SkRect& dstRect, float alpha, unsigned aaFlags)
2947 : fImage(std::move(image))
2948 , fSrcRect(srcRect)
2949 , fDstRect(dstRect)
2950 , fAlpha(alpha)
2951 , fAAFlags(aaFlags) {}
2952
2953///////////////////////////////////////////////////////////////////////////////
2954
Mike Reed5df49342016-11-12 08:06:55 -06002955std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002956 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002957 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002958 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002959 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002960
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002961 SkBitmap bitmap;
2962 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002963 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002964 }
Mike Reed12f77342017-11-08 11:19:52 -05002965
2966 return props ?
2967 skstd::make_unique<SkCanvas>(bitmap, *props) :
2968 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002969}
reedd5fa1a42014-08-09 11:08:05 -07002970
2971///////////////////////////////////////////////////////////////////////////////
2972
Florin Malitaee424ac2016-12-01 12:47:59 -05002973SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002974 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002975
Florin Malita439ace92016-12-02 12:05:41 -05002976SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002977 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002978
Herb Derbyefe39bc2018-05-01 17:06:20 -04002979SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002980 : INHERITED(device) {}
2981
Florin Malitaee424ac2016-12-01 12:47:59 -05002982SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2983 (void)this->INHERITED::getSaveLayerStrategy(rec);
2984 return kNoLayer_SaveLayerStrategy;
2985}
2986
Mike Reed148b7fd2018-12-18 17:38:18 -05002987bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2988 return false;
2989}
2990
Florin Malitaee424ac2016-12-01 12:47:59 -05002991///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002992
reed73603f32016-09-20 08:42:38 -07002993static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2994static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2995static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2996static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2997static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2998static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002999
3000///////////////////////////////////////////////////////////////////////////////////////////////////
3001
3002SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3003 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04003004 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05003005 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3006 SkIPoint origin = dev->getOrigin();
3007 SkMatrix ctm = this->getTotalMatrix();
3008 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3009
3010 SkIRect clip = fMCRec->fRasterClip.getBounds();
3011 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003012 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003013 clip.setEmpty();
3014 }
3015
3016 fAllocator->updateHandle(handle, ctm, clip);
3017 return handle;
3018 }
3019 return nullptr;
3020}
3021
3022static bool install(SkBitmap* bm, const SkImageInfo& info,
3023 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04003024 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05003025}
3026
3027SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3028 SkBitmap* bm) {
3029 SkRasterHandleAllocator::Rec rec;
3030 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3031 return nullptr;
3032 }
3033 return rec.fHandle;
3034}
3035
3036std::unique_ptr<SkCanvas>
3037SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3038 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04003039 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05003040 return nullptr;
3041 }
3042
3043 SkBitmap bm;
3044 Handle hndl;
3045
3046 if (rec) {
3047 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3048 } else {
3049 hndl = alloc->allocBitmap(info, &bm);
3050 }
3051 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3052}
Mike Reed7c9c9e42018-01-03 09:23:34 -05003053
3054///////////////////////////////////////////////////////////////////////////////////////////////////
3055
3056