blob: 0ea506b07c95d961e5c760ab2cb34b8a616d5fda [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"
21#include "include/private/SkArenaAlloc.h"
22#include "include/private/SkNx.h"
23#include "include/private/SkTo.h"
24#include "include/utils/SkNoDrawCanvas.h"
25#include "src/core/SkBitmapDevice.h"
26#include "src/core/SkCanvasPriv.h"
27#include "src/core/SkClipOpPriv.h"
28#include "src/core/SkClipStack.h"
29#include "src/core/SkDraw.h"
30#include "src/core/SkGlyphRun.h"
31#include "src/core/SkImageFilterCache.h"
Michael Ludwig08b260c2019-05-17 11:21:53 -040032#include "src/core/SkImageFilterPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050033#include "src/core/SkLatticeIter.h"
34#include "src/core/SkMSAN.h"
35#include "src/core/SkMakeUnique.h"
36#include "src/core/SkMatrixUtils.h"
37#include "src/core/SkPaintPriv.h"
38#include "src/core/SkRasterClip.h"
39#include "src/core/SkSpecialImage.h"
40#include "src/core/SkStrikeCache.h"
41#include "src/core/SkTLazy.h"
42#include "src/core/SkTextFormatParams.h"
43#include "src/core/SkTraceEvent.h"
44#include "src/image/SkImage_Base.h"
45#include "src/image/SkSurface_Base.h"
46#include "src/utils/SkPatchUtils.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040047
bungemand3ebb482015-08-05 13:57:49 -070048#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050051#include "include/gpu/GrContext.h"
52#include "src/gpu/SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053#endif
54
reede3b38ce2016-01-08 09:18:44 -080055#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050056#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080057
Mike Reed139e5e02017-03-08 11:29:33 -050058///////////////////////////////////////////////////////////////////////////////////////////////////
59
reedc83a2972015-07-16 07:40:45 -070060/*
61 * Return true if the drawing this rect would hit every pixels in the canvas.
62 *
63 * Returns false if
64 * - rect does not contain the canvas' bounds
65 * - paint is not fill
66 * - paint would blur or otherwise change the coverage of the rect
67 */
68bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
69 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070070 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
71 (int)kNone_ShaderOverrideOpacity,
72 "need_matching_enums0");
73 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
74 (int)kOpaque_ShaderOverrideOpacity,
75 "need_matching_enums1");
76 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
77 (int)kNotOpaque_ShaderOverrideOpacity,
78 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070079
80 const SkISize size = this->getBaseLayerSize();
81 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050082
83 // if we're clipped at all, we can't overwrite the entire surface
84 {
85 SkBaseDevice* base = this->getDevice();
86 SkBaseDevice* top = this->getTopDevice();
87 if (base != top) {
88 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
89 }
90 if (!base->clipIsWideOpen()) {
91 return false;
92 }
reedc83a2972015-07-16 07:40:45 -070093 }
94
95 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070096 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070097 return false; // conservative
98 }
halcanaryc5769b22016-08-10 07:13:21 -070099
100 SkRect devRect;
101 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
102 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700103 return false;
104 }
105 }
106
107 if (paint) {
108 SkPaint::Style paintStyle = paint->getStyle();
109 if (!(paintStyle == SkPaint::kFill_Style ||
110 paintStyle == SkPaint::kStrokeAndFill_Style)) {
111 return false;
112 }
113 if (paint->getMaskFilter() || paint->getLooper()
114 || paint->getPathEffect() || paint->getImageFilter()) {
115 return false; // conservative
116 }
117 }
118 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
119}
120
121///////////////////////////////////////////////////////////////////////////////////////////////////
122
reed@google.comda17f752012-08-16 18:27:05 +0000123// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124//#define SK_TRACE_SAVERESTORE
125
126#ifdef SK_TRACE_SAVERESTORE
127 static int gLayerCounter;
128 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
129 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
130
131 static int gRecCounter;
132 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
133 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
134
135 static int gCanvasCounter;
136 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
137 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
138#else
139 #define inc_layer()
140 #define dec_layer()
141 #define inc_rec()
142 #define dec_rec()
143 #define inc_canvas()
144 #define dec_canvas()
145#endif
146
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000147typedef SkTLazy<SkPaint> SkLazyPaint;
148
reedc83a2972015-07-16 07:40:45 -0700149void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000150 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700151 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
152 ? SkSurface::kDiscard_ContentChangeMode
153 : SkSurface::kRetain_ContentChangeMode);
154 }
155}
156
157void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
158 ShaderOverrideOpacity overrideOpacity) {
159 if (fSurfaceBase) {
160 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
161 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
162 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
163 // and therefore we don't care which mode we're in.
164 //
165 if (fSurfaceBase->outstandingImageSnapshot()) {
166 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
167 mode = SkSurface::kDiscard_ContentChangeMode;
168 }
169 }
170 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000171 }
172}
173
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000176/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 The clip/matrix/proc are fields that reflect the top of the save/restore
178 stack. Whenever the canvas changes, it marks a dirty flag, and then before
179 these are used (assuming we're not on a layer) we rebuild these cache
180 values: they reflect the top of the save stack, but translated and clipped
181 by the device's XY offset and bitmap-bounds.
182*/
183struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400184 DeviceCM* fNext;
185 sk_sp<SkBaseDevice> fDevice;
186 SkRasterClip fClip;
187 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
188 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400189 sk_sp<SkImage> fClipImage;
190 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191
Florin Malita53f77bd2017-04-28 13:48:37 -0400192 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000193 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700194 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400195 , fDevice(std::move(device))
196 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700197 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000198 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400199 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400200 {}
reed@google.com4b226022011-01-11 18:32:13 +0000201
mtkleinfeaadee2015-04-08 11:25:48 -0700202 void reset(const SkIRect& bounds) {
203 SkASSERT(!fPaint);
204 SkASSERT(!fNext);
205 SkASSERT(fDevice);
206 fClip.setRect(bounds);
207 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208};
209
Mike Reed148b7fd2018-12-18 17:38:18 -0500210namespace {
211// Encapsulate state needed to restore from saveBehind()
212struct BackImage {
213 sk_sp<SkSpecialImage> fImage;
214 SkIPoint fLoc;
215};
216}
217
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218/* This is the record we keep for each save/restore level in the stack.
219 Since a level optionally copies the matrix and/or stack, we have pointers
220 for these fields. If the value is copied for this level, the copy is
221 stored in the ...Storage field, and the pointer points to that. If the
222 value is not copied for this level, we ignore ...Storage, and just point
223 at the corresponding value in the previous level in the stack.
224*/
225class SkCanvas::MCRec {
226public:
Mike Reed148b7fd2018-12-18 17:38:18 -0500227 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 /* If there are any layers in the stack, this points to the top-most
229 one that is at or below this level in the stack (so we know what
230 bitmap/device to draw into from this level. This value is NOT
231 reference counted, since the real owner is either our fLayer field,
232 or a previous one in a lower level.)
233 */
Mike Reed148b7fd2018-12-18 17:38:18 -0500234 DeviceCM* fTopLayer;
235 std::unique_ptr<BackImage> fBackImage;
236 SkConservativeClip fRasterClip;
237 SkMatrix fMatrix;
238 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239
Mike Reeda1361362017-03-07 09:37:29 -0500240 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700241 fLayer = nullptr;
242 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800243 fMatrix.reset();
244 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700245
reedd9544982014-09-09 18:46:22 -0700246 // don't bother initializing fNext
247 inc_rec();
248 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400249 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700250 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700251 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800252 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700253
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 // don't bother initializing fNext
255 inc_rec();
256 }
257 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700258 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259 dec_rec();
260 }
mtkleinfeaadee2015-04-08 11:25:48 -0700261
262 void reset(const SkIRect& bounds) {
263 SkASSERT(fLayer);
264 SkASSERT(fDeferredSaveCount == 0);
265
266 fMatrix.reset();
267 fRasterClip.setRect(bounds);
268 fLayer->reset(bounds);
269 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270};
271
Mike Reeda1361362017-03-07 09:37:29 -0500272class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273public:
Mike Reeda1361362017-03-07 09:37:29 -0500274 SkDrawIter(SkCanvas* canvas)
275 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
276 {}
reed@google.com4b226022011-01-11 18:32:13 +0000277
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000279 const DeviceCM* rec = fCurrLayer;
280 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400281 fDevice = rec->fDevice.get();
282 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700284 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 return true;
286 }
287 return false;
288 }
reed@google.com4b226022011-01-11 18:32:13 +0000289
reed@google.com6f8f2922011-03-04 22:27:10 +0000290 int getX() const { return fDevice->getOrigin().x(); }
291 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000293
Mike Reed99330ba2017-02-22 11:01:08 -0500294 SkBaseDevice* fDevice;
295
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 const DeviceCM* fCurrLayer;
298 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299};
300
Florin Malita713b8ef2017-04-28 10:57:24 -0400301#define FOR_EACH_TOP_DEVICE( code ) \
302 do { \
303 DeviceCM* layer = fMCRec->fTopLayer; \
304 while (layer) { \
305 SkBaseDevice* device = layer->fDevice.get(); \
306 if (device) { \
307 code; \
308 } \
309 layer = layer->fNext; \
310 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500311 } while (0)
312
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313/////////////////////////////////////////////////////////////////////////////
314
reeddbc3cef2015-04-29 12:18:57 -0700315static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
316 return lazy->isValid() ? lazy->get() : lazy->set(orig);
317}
318
319/**
320 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700321 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700322 */
reedd053ce92016-03-22 10:17:23 -0700323static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700324 SkImageFilter* imgf = paint.getImageFilter();
325 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700326 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700327 }
328
reedd053ce92016-03-22 10:17:23 -0700329 SkColorFilter* imgCFPtr;
330 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700331 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700332 }
reedd053ce92016-03-22 10:17:23 -0700333 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700334
335 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700336 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700337 // there is no existing paint colorfilter, so we can just return the imagefilter's
338 return imgCF;
339 }
340
341 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
342 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500343 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700344}
345
senorblanco87e066e2015-10-28 11:23:36 -0700346/**
347 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
348 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
349 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
350 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
351 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
352 * conservative "effective" bounds based on the settings in the paint... with one exception. This
353 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
354 * deliberately ignored.
355 */
356static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
357 const SkRect& rawBounds,
358 SkRect* storage) {
359 SkPaint tmpUnfiltered(paint);
360 tmpUnfiltered.setImageFilter(nullptr);
361 if (tmpUnfiltered.canComputeFastBounds()) {
362 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
363 } else {
364 return rawBounds;
365 }
366}
367
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368class AutoDrawLooper {
369public:
senorblanco87e066e2015-10-28 11:23:36 -0700370 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
371 // paint. It's used to determine the size of the offscreen layer for filters.
372 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700373 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700374 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000375 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700376 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000377 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700378 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000379 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380
reedd053ce92016-03-22 10:17:23 -0700381 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700382 if (simplifiedCF) {
383 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700384 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700385 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700386 fPaint = paint;
387 }
388
389 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700390 /**
391 * We implement ImageFilters for a given draw by creating a layer, then applying the
392 * imagefilter to the pixels of that layer (its backing surface/image), and then
393 * we call restore() to xfer that layer to the main canvas.
394 *
395 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
396 * 2. Generate the src pixels:
397 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
398 * return (fPaint). We then draw the primitive (using srcover) into a cleared
399 * buffer/surface.
400 * 3. Restore the layer created in #1
401 * The imagefilter is passed the buffer/surface from the layer (now filled with the
402 * src pixels of the primitive). It returns a new "filtered" buffer, which we
403 * draw onto the previous layer using the xfermode from the original paint.
404 */
reed@google.com8926b162012-03-23 15:36:36 +0000405 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500406 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700407 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700408 SkRect storage;
409 if (rawBounds) {
410 // Make rawBounds include all paint outsets except for those due to image filters.
411 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
412 }
reedbfd5f172016-01-07 11:28:08 -0800413 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700414 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700415 fTempLayerForImageFilter = true;
416 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000417 }
418
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000419 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500420 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000421 fIsSimple = false;
422 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700423 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000424 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400425 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000426 }
427 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000428
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700430 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000431 fCanvas->internalRestore();
432 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000433 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000435
reed@google.com4e2b3d32011-04-07 14:18:59 +0000436 const SkPaint& paint() const {
437 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400438 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000439 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000441
Ben Wagner2c312c42018-06-27 14:46:46 -0400442 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000443 if (fDone) {
444 return false;
445 } else if (fIsSimple) {
446 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000447 return !fPaint->nothingToDraw();
448 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400449 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000450 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000451 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000452
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500454 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700455 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000456 SkCanvas* fCanvas;
457 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000458 const SkPaint* fPaint;
459 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700460 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000461 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000462 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000463 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400464 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000465
Ben Wagner2c312c42018-06-27 14:46:46 -0400466 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000467};
468
Ben Wagner2c312c42018-06-27 14:46:46 -0400469bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700470 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000471 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400472 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000473
reeddbc3cef2015-04-29 12:18:57 -0700474 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
475 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400476 // never want our downstream clients (i.e. devices) to see loopers
477 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000478
reed5c476fb2015-04-20 08:04:21 -0700479 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700480 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700481 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000483
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000484 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000485 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000486 return false;
487 }
reed@google.com129ec222012-05-15 13:24:09 +0000488 fPaint = paint;
489
490 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400491 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000492 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000493 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000494 return true;
495}
496
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497////////// macros to place around the internal draw calls //////////////////
498
reed3aafe112016-08-18 12:45:34 -0700499#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
500 this->predrawNotify(); \
501 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400502 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800503 SkDrawIter iter(this);
504
505
Ben Wagner2c312c42018-06-27 14:46:46 -0400506#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000507 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700508 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400509 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000510 SkDrawIter iter(this);
511
Ben Wagner2c312c42018-06-27 14:46:46 -0400512#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000513 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700514 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400515 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000517
Ben Wagner2c312c42018-06-27 14:46:46 -0400518#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700519 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700520 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400521 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700522 SkDrawIter iter(this);
523
reed@google.com4e2b3d32011-04-07 14:18:59 +0000524#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525
526////////////////////////////////////////////////////////////////////////////
527
msarettfbfa2582016-08-12 08:29:08 -0700528static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
529 if (bounds.isEmpty()) {
530 return SkRect::MakeEmpty();
531 }
532
533 // Expand bounds out by 1 in case we are anti-aliasing. We store the
534 // bounds as floats to enable a faster quick reject implementation.
535 SkRect dst;
536 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
537 return dst;
538}
539
mtkleinfeaadee2015-04-08 11:25:48 -0700540void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
541 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700542 fMCRec->reset(bounds);
543
544 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500545 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400546 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700547 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700548 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700549}
550
Hal Canary363a3f82018-10-04 11:04:48 -0400551void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000552 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800553 fSaveCount = 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554
555 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500556 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500557 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700558 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559
reeda499f902015-05-01 09:34:31 -0700560 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
561 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400562 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700563
reed@android.com8a1c16f2008-12-17 15:59:43 +0000564 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000565
halcanary96fcdcc2015-08-27 07:41:13 -0700566 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000567
reedf92c8662014-08-18 08:02:43 -0700568 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700569 // The root device and the canvas should always have the same pixel geometry
570 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800571 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700572 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500573
Mike Reedc42a1cd2017-02-14 14:25:14 -0500574 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700575 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400576
Herb Derby59d997a2018-06-07 12:44:09 -0400577 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578}
579
reed@google.comcde92112011-07-06 20:00:52 +0000580SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000581 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700582 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000583{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000584 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000585
Hal Canary363a3f82018-10-04 11:04:48 -0400586 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000587}
588
reed96a857e2015-01-25 10:33:58 -0800589SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000590 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800591 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000592{
593 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400594 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400595 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700596}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000597
Hal Canary363a3f82018-10-04 11:04:48 -0400598SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700599 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700600 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700601{
602 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700603
Mike Reed566e53c2017-03-10 10:49:45 -0500604 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400605 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700606}
607
Herb Derbyefe39bc2018-05-01 17:06:20 -0400608SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000609 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700610 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000611{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700613
Hal Canary363a3f82018-10-04 11:04:48 -0400614 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700615}
616
reed4a8126e2014-09-22 07:29:03 -0700617SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700618 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700619 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700620{
621 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700622
Mike Reed910ca0f2018-04-25 13:04:05 -0400623 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400624 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700625}
reed29c857d2014-09-21 10:25:07 -0700626
Mike Reed356f7c22017-01-10 11:58:39 -0500627SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
628 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700629 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
630 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500631 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700632{
633 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700634
Mike Reed910ca0f2018-04-25 13:04:05 -0400635 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400636 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637}
638
Mike Reed356f7c22017-01-10 11:58:39 -0500639SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
640
Matt Sarett31f99ce2017-04-11 08:46:01 -0400641#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
642SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
643 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
644 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
645 , fAllocator(nullptr)
646{
647 inc_canvas();
648
649 SkBitmap tmp(bitmap);
650 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400651 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400652 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400653}
654#endif
655
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656SkCanvas::~SkCanvas() {
657 // free up the contents of our deque
658 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000659
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660 this->internalRestore(); // restore the last, since we're going away
661
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 dec_canvas();
663}
664
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665///////////////////////////////////////////////////////////////////////////////
666
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000667void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700668 this->onFlush();
669}
670
671void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000672 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000673 if (device) {
674 device->flush();
675 }
676}
677
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000678SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000679 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000680 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
681}
682
senorblancoafc7cce2016-02-02 18:44:15 -0800683SkIRect SkCanvas::getTopLayerBounds() const {
684 SkBaseDevice* d = this->getTopDevice();
685 if (!d) {
686 return SkIRect::MakeEmpty();
687 }
688 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
689}
690
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000691SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000693 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000694 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400695 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696}
697
Florin Malita0ed3b642017-01-13 16:56:38 +0000698SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400699 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000700}
701
Mike Reed353196f2017-07-21 11:01:18 -0400702bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000703 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400704 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000705}
706
Mike Reed353196f2017-07-21 11:01:18 -0400707bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
708 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400709}
710
711bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
712 SkPixmap pm;
713 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
714}
715
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000716bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400717 SkPixmap pm;
718 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700719 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000720 }
721 return false;
722}
723
Matt Sarett03dd6d52017-01-23 12:15:09 -0500724bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000725 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000726 SkBaseDevice* device = this->getDevice();
727 if (!device) {
728 return false;
729 }
730
Matt Sarett03dd6d52017-01-23 12:15:09 -0500731 // This check gives us an early out and prevents generation ID churn on the surface.
732 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
733 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
734 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
735 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000736 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000737
Matt Sarett03dd6d52017-01-23 12:15:09 -0500738 // Tell our owning surface to bump its generation ID.
739 const bool completeOverwrite =
740 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700741 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700742
Matt Sarett03dd6d52017-01-23 12:15:09 -0500743 // This can still fail, most notably in the case of a invalid color type or alpha type
744 // conversion. We could pull those checks into this function and avoid the unnecessary
745 // generation ID bump. But then we would be performing those checks twice, since they
746 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400747 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000748}
reed@google.com51df9e32010-12-23 19:29:18 +0000749
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750//////////////////////////////////////////////////////////////////////////////
751
reed2ff1fce2014-12-11 07:07:37 -0800752void SkCanvas::checkForDeferredSave() {
753 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800754 this->doSave();
755 }
756}
757
reedf0090cb2014-11-26 08:55:51 -0800758int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800759#ifdef SK_DEBUG
760 int count = 0;
761 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
762 for (;;) {
763 const MCRec* rec = (const MCRec*)iter.next();
764 if (!rec) {
765 break;
766 }
767 count += 1 + rec->fDeferredSaveCount;
768 }
769 SkASSERT(count == fSaveCount);
770#endif
771 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800772}
773
774int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800775 fSaveCount += 1;
776 fMCRec->fDeferredSaveCount += 1;
777 return this->getSaveCount() - 1; // return our prev value
778}
779
780void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800781 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700782
783 SkASSERT(fMCRec->fDeferredSaveCount > 0);
784 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800785 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800786}
787
788void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800789 if (fMCRec->fDeferredSaveCount > 0) {
790 SkASSERT(fSaveCount > 1);
791 fSaveCount -= 1;
792 fMCRec->fDeferredSaveCount -= 1;
793 } else {
794 // check for underflow
795 if (fMCStack.count() > 1) {
796 this->willRestore();
797 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700798 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800799 this->internalRestore();
800 this->didRestore();
801 }
reedf0090cb2014-11-26 08:55:51 -0800802 }
803}
804
805void SkCanvas::restoreToCount(int count) {
806 // sanity check
807 if (count < 1) {
808 count = 1;
809 }
mtkleinf0f14112014-12-12 08:46:25 -0800810
reedf0090cb2014-11-26 08:55:51 -0800811 int n = this->getSaveCount() - count;
812 for (int i = 0; i < n; ++i) {
813 this->restore();
814 }
815}
816
reed2ff1fce2014-12-11 07:07:37 -0800817void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700819 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000821
Mike Reedc42a1cd2017-02-14 14:25:14 -0500822 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823}
824
reed4960eee2015-12-18 07:09:18 -0800825bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400826 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827}
828
reed4960eee2015-12-18 07:09:18 -0800829bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700830 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500831 SkIRect clipBounds = this->getDeviceClipBounds();
832 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000833 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000834 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000835
reed96e657d2015-03-10 17:30:07 -0700836 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
837
Robert Phillips12078432018-05-17 11:17:39 -0400838 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
839 // If the image filter DAG affects transparent black then we will need to render
840 // out to the clip bounds
841 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000842 }
Robert Phillips12078432018-05-17 11:17:39 -0400843
844 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700845 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000846 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700847 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400848 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000849 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400850 inputSaveLayerBounds = clipBounds;
851 }
852
853 if (imageFilter) {
854 // expand the clip bounds by the image filter DAG to include extra content that might
855 // be required by the image filters.
856 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
857 SkImageFilter::kReverse_MapDirection,
858 &inputSaveLayerBounds);
859 }
860
861 SkIRect clippedSaveLayerBounds;
862 if (bounds) {
863 // For better or for worse, user bounds currently act as a hard clip on the layer's
864 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
865 clippedSaveLayerBounds = inputSaveLayerBounds;
866 } else {
867 // If there are no user bounds, we don't want to artificially restrict the resulting
868 // layer bounds, so allow the expanded clip bounds free reign.
869 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800871
872 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400873 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800874 if (BoundsAffectsClip(saveLayerFlags)) {
875 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
876 fMCRec->fRasterClip.setEmpty();
877 fDeviceClipBounds.setEmpty();
878 }
879 return false;
880 }
Robert Phillips12078432018-05-17 11:17:39 -0400881 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000882
reed4960eee2015-12-18 07:09:18 -0800883 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700884 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400885 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
886 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000887 }
888
889 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400890 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000891 }
Robert Phillips12078432018-05-17 11:17:39 -0400892
junov@chromium.orga907ac32012-02-24 21:54:07 +0000893 return true;
894}
895
reed4960eee2015-12-18 07:09:18 -0800896int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
897 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000898}
899
Cary Clarke041e312018-03-06 13:00:52 -0500900int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700901 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400902 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
903 // no need for the layer (or any of the draws until the matching restore()
904 this->save();
905 this->clipRect({0,0,0,0});
906 } else {
907 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
908 fSaveCount += 1;
909 this->internalSaveLayer(rec, strategy);
910 }
reed4960eee2015-12-18 07:09:18 -0800911 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800912}
913
Mike Reed148b7fd2018-12-18 17:38:18 -0500914int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
915 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
916 // Assuming clips never expand, if the request bounds is outside of the current clip
917 // there is no need to copy/restore the area, so just devolve back to a regular save.
918 this->save();
919 } else {
920 bool doTheWork = this->onDoSaveBehind(bounds);
921 fSaveCount += 1;
922 this->internalSave();
923 if (doTheWork) {
924 this->internalSaveBehind(bounds);
925 }
926 }
927 return this->getSaveCount() - 1;
928}
929
reeda2217ef2016-07-20 06:04:34 -0700930void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500931 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500932 const SkMatrix& ctm) {
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400933 SkPaint p;
Michael Ludwig08b260c2019-05-17 11:21:53 -0400934 SkIRect snapBounds = SkIRect::MakeXYWH(dstOrigin.x() - src->getOrigin().x(),
935 dstOrigin.y() - src->getOrigin().y(),
936 dst->width(), dst->height());
937 int x = 0;
938 int y = 0;
939
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400940 if (filter) {
Michael Ludwig08b260c2019-05-17 11:21:53 -0400941 // Calculate expanded snap bounds
942 SkIRect newBounds = filter->filterBounds(
943 snapBounds, ctm, SkImageFilter::kReverse_MapDirection, &snapBounds);
944 // Must clamp to valid src since the filter or rotations may expand beyond what's readable
945 SkIRect srcR = SkIRect::MakeWH(src->width(), src->height());
946 if (!newBounds.intersect(srcR)) {
947 return;
948 }
949
950 x = newBounds.fLeft - snapBounds.fLeft;
951 y = newBounds.fTop - snapBounds.fTop;
952 snapBounds = newBounds;
953
954 SkMatrix localCTM;
955 sk_sp<SkImageFilter> modifiedFilter = SkApplyCTMToBackdropFilter(filter, ctm, &localCTM);
956 // Account for the origin offset in the CTM
957 localCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
958
959 // In this case we always wrap the filter (even when it's the original) with 'localCTM'
960 // since there's no device CTM stack that provides it to the image filter context.
961 // FIXME skbug.com/9074 - once perspective is properly supported, drop the
962 // localCTM.hasPerspective condition from assert.
963 SkASSERT(localCTM.isScaleTranslate() || filter->canHandleComplexCTM() ||
964 localCTM.hasPerspective());
965 p.setImageFilter(modifiedFilter->makeWithLocalMatrix(localCTM));
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400966 }
967
Michael Ludwig08b260c2019-05-17 11:21:53 -0400968 auto special = src->snapBackImage(snapBounds);
reeda2217ef2016-07-20 06:04:34 -0700969 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400970 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700971 }
robertphillips7354a4b2015-12-16 05:08:27 -0800972}
reed70ee31b2015-12-10 13:44:45 -0800973
Mike Reed25394292019-03-07 09:36:36 -0500974// This is shared by all backends, but contains raster-specific thoughts. Can we defer to the
975// device to perform this?
Mike Kleine083f7c2018-02-07 12:54:27 -0500976static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500977 // Need to force L32 for now if we have an image filter.
Mike Reed25394292019-03-07 09:36:36 -0500978 // If filters ever support other colortypes, e.g. F16, we can modify this check.
Mike Klein649fb732018-02-26 15:09:16 -0500979 if (paint && paint->getImageFilter()) {
Mike Reed25394292019-03-07 09:36:36 -0500980 // TODO: can we query the imagefilter, to see if it can handle floats (so we don't always
981 // use N32 when the layer itself was float)?
982 return SkImageInfo::MakeN32Premul(w, h, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800983 }
Mike Klein649fb732018-02-26 15:09:16 -0500984
985 SkColorType ct = prev.colorType();
986 if (prev.bytesPerPixel() <= 4) {
987 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
988 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
989 ct = kN32_SkColorType;
990 }
991 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800992}
993
reed4960eee2015-12-18 07:09:18 -0800994void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700995 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800996 const SkRect* bounds = rec.fBounds;
997 const SkPaint* paint = rec.fPaint;
998 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
999
Mike Reed5532c2a2019-02-23 12:00:32 -05001000 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
1001 // regardless of any hint-rect from the caller. skbug.com/8783
1002 if (rec.fBackdrop) {
1003 bounds = nullptr;
1004 }
1005
reed8c30a812016-04-20 16:36:51 -07001006 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001007 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001008 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -04001009 MCRec* modifiedRec = nullptr;
Michael Ludwig08b260c2019-05-17 11:21:53 -04001010
reed8c30a812016-04-20 16:36:51 -07001011 /*
Michael Ludwig08b260c2019-05-17 11:21:53 -04001012 * Many ImageFilters (so far) do not (on their own) correctly handle matrices (CTM) that
1013 * contain rotation/skew/etc. We rely on applyCTM to create a new image filter DAG as needed to
1014 * accommodate this, but it requires update the CTM we use when drawing into the layer.
reed8c30a812016-04-20 16:36:51 -07001015 *
1016 * 1. Stash off the current CTM
Michael Ludwig08b260c2019-05-17 11:21:53 -04001017 * 2. Apply the CTM to imagefilter, which decomposes it into simple and complex transforms
1018 * if necessary.
1019 * 3. Wack the CTM to be the remaining scale matrix and use the modified imagefilter, which
1020 * is a MatrixImageFilter that contains the complex matrix.
reed8c30a812016-04-20 16:36:51 -07001021 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
Michael Ludwig08b260c2019-05-17 11:21:53 -04001022 * 5. During restore, the MatrixImageFilter automatically applies complex stage to the output
reed8c30a812016-04-20 16:36:51 -07001023 * of the original imagefilter, and draw that (via drawSprite)
1024 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1025 *
1026 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1027 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1028 */
Michael Ludwig08b260c2019-05-17 11:21:53 -04001029 if (imageFilter) {
1030 SkMatrix modifiedCTM;
1031 sk_sp<SkImageFilter> modifiedFilter = SkApplyCTMToFilter(imageFilter, stashedMatrix,
1032 &modifiedCTM);
1033 if (!SkIsSameFilter(modifiedFilter.get(), imageFilter)) {
1034 // The original filter couldn't support the CTM entirely
1035 SkASSERT(modifiedCTM.isScaleTranslate() || imageFilter->canHandleComplexCTM());
1036 modifiedRec = fMCRec;
1037 this->internalSetMatrix(modifiedCTM);
1038 SkPaint* p = lazyP.set(*paint);
1039 p->setImageFilter(std::move(modifiedFilter));
1040 imageFilter = p->getImageFilter();
1041 paint = p;
1042 }
1043 // Else the filter didn't change, so modifiedCTM == stashedMatrix and there's nothing
1044 // left to do since the stack already has that as the CTM.
reed8c30a812016-04-20 16:36:51 -07001045 }
reed8c30a812016-04-20 16:36:51 -07001046
junov@chromium.orga907ac32012-02-24 21:54:07 +00001047 // do this before we create the layer. We don't call the public save() since
1048 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001049 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001050
junov@chromium.orga907ac32012-02-24 21:54:07 +00001051 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001052 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001053 if (modifiedRec) {
1054 // In this case there will be no layer in which to stash the matrix so we need to
1055 // revert the prior MCRec to its earlier state.
1056 modifiedRec->fMatrix = stashedMatrix;
1057 }
reed2ff1fce2014-12-11 07:07:37 -08001058 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059 }
1060
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001061 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1062 // the clipRectBounds() call above?
1063 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001064 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001065 }
1066
reed8dc0ccb2015-03-20 06:32:52 -07001067 SkPixelGeometry geo = fProps.pixelGeometry();
1068 if (paint) {
reed76033be2015-03-14 10:54:31 -07001069 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001070 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001071 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001072 }
1073 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001074
robertphillips5139e502016-07-19 05:10:40 -07001075 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001076 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001077 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001078 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001079 }
reedb2db8982014-11-13 12:41:02 -08001080
Mike Kleine083f7c2018-02-07 12:54:27 -05001081 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001082
Hal Canary704cd322016-11-07 14:13:52 -05001083 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001084 {
Florin Malita07e4adf2019-01-07 16:34:18 -05001085 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType();
reeddaa57bf2015-05-15 10:39:17 -07001086 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001087 const bool trackCoverage =
1088 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001089 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001090 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001091 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001092 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001093 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1094 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001095 return;
reed61f501f2015-04-29 08:34:00 -07001096 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001097 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001098 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099
Mike Reedb43a3e02017-02-11 10:18:58 -05001100 // only have a "next" if this new layer doesn't affect the clip (rare)
1101 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001102 fMCRec->fLayer = layer;
1103 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001104
Mike Reedc61abee2017-02-28 17:45:27 -05001105 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001106 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001107 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001108 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001109
Mike Reedc42a1cd2017-02-14 14:25:14 -05001110 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1111
1112 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1113 if (layer->fNext) {
1114 // need to punch a hole in the previous device, so we don't draw there, given that
1115 // the new top-layer will allow drawing to happen "below" it.
1116 SkRegion hole(ir);
1117 do {
1118 layer = layer->fNext;
1119 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1120 } while (layer->fNext);
1121 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001122}
1123
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001124int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001125 if (0xFF == alpha) {
1126 return this->saveLayer(bounds, nullptr);
1127 } else {
1128 SkPaint tmpPaint;
1129 tmpPaint.setAlpha(alpha);
1130 return this->saveLayer(bounds, &tmpPaint);
1131 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001132}
1133
Mike Reed148b7fd2018-12-18 17:38:18 -05001134void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1135 SkIRect devBounds;
1136 if (localBounds) {
1137 SkRect tmp;
1138 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1139 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1140 devBounds.setEmpty();
1141 }
1142 } else {
1143 devBounds = this->getDeviceClipBounds();
1144 }
1145 if (devBounds.isEmpty()) {
1146 return;
1147 }
1148
1149 SkBaseDevice* device = this->getTopDevice();
1150 if (nullptr == device) { // Do we still need this check???
1151 return;
1152 }
1153
1154 // need the bounds relative to the device itself
1155 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1156
1157 auto backImage = device->snapBackImage(devBounds);
1158 if (!backImage) {
1159 return;
1160 }
1161
1162 // we really need the save, so we can wack the fMCRec
1163 this->checkForDeferredSave();
1164
1165 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1166
1167 SkPaint paint;
1168 paint.setBlendMode(SkBlendMode::kClear);
Mike Reed9adc82c2019-04-23 10:28:13 -04001169 this->drawClippedToSaveBehind(paint);
Mike Reed148b7fd2018-12-18 17:38:18 -05001170}
1171
reed@android.com8a1c16f2008-12-17 15:59:43 +00001172void SkCanvas::internalRestore() {
1173 SkASSERT(fMCStack.count() != 0);
1174
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001175 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001176 DeviceCM* layer = fMCRec->fLayer; // may be null
1177 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001178 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001179
Mike Reed148b7fd2018-12-18 17:38:18 -05001180 // move this out before we do the actual restore
1181 auto backImage = std::move(fMCRec->fBackImage);
1182
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183 // now do the normal restore()
1184 fMCRec->~MCRec(); // balanced in save()
1185 fMCStack.pop_back();
1186 fMCRec = (MCRec*)fMCStack.back();
1187
Mike Reedc42a1cd2017-02-14 14:25:14 -05001188 if (fMCRec) {
1189 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1190 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001191
Mike Reed148b7fd2018-12-18 17:38:18 -05001192 if (backImage) {
1193 SkPaint paint;
1194 paint.setBlendMode(SkBlendMode::kDstOver);
1195 const int x = backImage->fLoc.x();
1196 const int y = backImage->fLoc.y();
1197 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1198 nullptr, SkMatrix::I());
1199 }
1200
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1202 since if we're being recorded, we don't want to record this (the
1203 recorder will have already recorded the restore).
1204 */
bsalomon49f085d2014-09-05 13:34:00 -07001205 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001206 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001207 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001208 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001209 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001210 layer->fPaint.get(),
1211 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001212 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001213 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001214 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001215 delete layer;
reedb679ca82015-04-07 04:40:48 -07001216 } else {
1217 // we're at the root
reeda499f902015-05-01 09:34:31 -07001218 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001219 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001220 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001222 }
msarettfbfa2582016-08-12 08:29:08 -07001223
1224 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001225 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001226 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1227 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228}
1229
reede8f30622016-03-23 18:59:25 -07001230sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001231 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001232 props = &fProps;
1233 }
1234 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001235}
1236
reede8f30622016-03-23 18:59:25 -07001237sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001238 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001239 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001240}
1241
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001242SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001243 return this->onImageInfo();
1244}
1245
1246SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001247 SkBaseDevice* dev = this->getDevice();
1248 if (dev) {
1249 return dev->imageInfo();
1250 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001251 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001252 }
1253}
1254
brianosman898235c2016-04-06 07:38:23 -07001255bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001256 return this->onGetProps(props);
1257}
1258
1259bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001260 SkBaseDevice* dev = this->getDevice();
1261 if (dev) {
1262 if (props) {
1263 *props = fProps;
1264 }
1265 return true;
1266 } else {
1267 return false;
1268 }
1269}
1270
reed6ceeebd2016-03-09 14:26:26 -08001271bool SkCanvas::peekPixels(SkPixmap* pmap) {
1272 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001273}
1274
reed884e97c2015-05-26 11:31:54 -07001275bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001276 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001277 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001278}
1279
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001280void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001281 SkPixmap pmap;
1282 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001283 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001284 }
1285 if (info) {
1286 *info = pmap.info();
1287 }
1288 if (rowBytes) {
1289 *rowBytes = pmap.rowBytes();
1290 }
1291 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001292 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001293 }
reed884e97c2015-05-26 11:31:54 -07001294 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001295}
1296
reed884e97c2015-05-26 11:31:54 -07001297bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001298 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001299 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001300}
1301
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303
Mike Reed8bcd1282019-03-13 16:51:54 -04001304// In our current design/features, we should never have a layer (src) in a different colorspace
1305// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1306// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1307// colorspace.
1308static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1309 SkASSERT(src == dst);
1310}
1311
Florin Malita53f77bd2017-04-28 13:48:37 -04001312void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1313 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001315 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001316 paint = &tmp;
1317 }
reed@google.com4b226022011-01-11 18:32:13 +00001318
Ben Wagner2c312c42018-06-27 14:46:46 -04001319 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001320
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001322 SkBaseDevice* dstDev = iter.fDevice;
Mike Reed8bcd1282019-03-13 16:51:54 -04001323 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1324 srcDev->imageInfo().colorSpace());
reed@google.com76dd2772012-01-05 21:15:07 +00001325 paint = &looper.paint();
1326 SkImageFilter* filter = paint->getImageFilter();
1327 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001328 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001329 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1330 if (specialImage) {
Mike Reed8bcd1282019-03-13 16:51:54 -04001331 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1332 specialImage->getColorSpace());
Florin Malita53f77bd2017-04-28 13:48:37 -04001333 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1334 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001335 }
reed@google.com76dd2772012-01-05 21:15:07 +00001336 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001337 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001338 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339 }
reeda2217ef2016-07-20 06:04:34 -07001340
reed@google.com4e2b3d32011-04-07 14:18:59 +00001341 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342}
1343
reed32704672015-12-16 08:27:10 -08001344/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001345
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001346void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001347 if (dx || dy) {
1348 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001349 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001350
reedfe69b502016-09-12 06:31:48 -07001351 // Translate shouldn't affect the is-scale-translateness of the matrix.
1352 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001353
Mike Reedc42a1cd2017-02-14 14:25:14 -05001354 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001355
reedfe69b502016-09-12 06:31:48 -07001356 this->didTranslate(dx,dy);
1357 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001358}
1359
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001360void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001361 SkMatrix m;
1362 m.setScale(sx, sy);
1363 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001364}
1365
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001366void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001367 SkMatrix m;
1368 m.setRotate(degrees);
1369 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001370}
1371
bungeman7438bfc2016-07-12 15:01:19 -07001372void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1373 SkMatrix m;
1374 m.setRotate(degrees, px, py);
1375 this->concat(m);
1376}
1377
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001378void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001379 SkMatrix m;
1380 m.setSkew(sx, sy);
1381 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001382}
1383
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001384void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001385 if (matrix.isIdentity()) {
1386 return;
1387 }
1388
reed2ff1fce2014-12-11 07:07:37 -08001389 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001390 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001391 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001392
Mike Reed7627fa52017-02-08 10:07:53 -05001393 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001394
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001395 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001396}
1397
reed8c30a812016-04-20 16:36:51 -07001398void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001399 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001400 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001401
Mike Reedc42a1cd2017-02-14 14:25:14 -05001402 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001403}
1404
1405void SkCanvas::setMatrix(const SkMatrix& matrix) {
1406 this->checkForDeferredSave();
1407 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001408 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409}
1410
reed@android.com8a1c16f2008-12-17 15:59:43 +00001411void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001412 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413}
1414
1415//////////////////////////////////////////////////////////////////////////////
1416
Mike Reedc1f77742016-12-09 09:00:50 -05001417void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001418 if (!rect.isFinite()) {
1419 return;
1420 }
reed2ff1fce2014-12-11 07:07:37 -08001421 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001422 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1423 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001424}
1425
Mike Reedc1f77742016-12-09 09:00:50 -05001426void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001427 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001428
Mike Reed7627fa52017-02-08 10:07:53 -05001429 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001430
reedc64eff52015-11-21 12:39:45 -08001431 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001432 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1433 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001434 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001435}
1436
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001437void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1438 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001439 if (fClipRestrictionRect.isEmpty()) {
1440 // we notify the device, but we *dont* resolve deferred saves (since we're just
1441 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001442 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001443 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001444 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001445 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001446 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001447 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001448 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1449 }
1450}
1451
Mike Reedc1f77742016-12-09 09:00:50 -05001452void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001453 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001454 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001455 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001456 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1457 } else {
1458 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001459 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001460}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001461
Mike Reedc1f77742016-12-09 09:00:50 -05001462void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001463 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001464
Brian Salomona3b45d42016-10-03 11:36:16 -04001465 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001466
Mike Reed7627fa52017-02-08 10:07:53 -05001467 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001468
Mike Reed20800c82017-11-15 16:09:04 -05001469 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1470 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001471 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001472}
1473
Mike Reedc1f77742016-12-09 09:00:50 -05001474void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001475 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001476 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001477
1478 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1479 SkRect r;
1480 if (path.isRect(&r)) {
1481 this->onClipRect(r, op, edgeStyle);
1482 return;
1483 }
1484 SkRRect rrect;
1485 if (path.isOval(&r)) {
1486 rrect.setOval(r);
1487 this->onClipRRect(rrect, op, edgeStyle);
1488 return;
1489 }
1490 if (path.isRRect(&rrect)) {
1491 this->onClipRRect(rrect, op, edgeStyle);
1492 return;
1493 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001494 }
robertphillips39f05382015-11-24 09:30:12 -08001495
1496 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001497}
1498
Mike Reedc1f77742016-12-09 09:00:50 -05001499void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001500 AutoValidateClip avc(this);
1501
Brian Salomona3b45d42016-10-03 11:36:16 -04001502 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001503
Mike Reed7627fa52017-02-08 10:07:53 -05001504 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505
Brian Salomona3b45d42016-10-03 11:36:16 -04001506 const SkPath* rasterClipPath = &path;
1507 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001508 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1509 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001510 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511}
1512
Mike Reedc1f77742016-12-09 09:00:50 -05001513void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001514 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001515 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001516}
1517
Mike Reedc1f77742016-12-09 09:00:50 -05001518void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001519 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001520
reed@google.com5c3d1472011-02-22 19:12:23 +00001521 AutoValidateClip avc(this);
1522
Mike Reed20800c82017-11-15 16:09:04 -05001523 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001524 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001525}
1526
reed@google.com819c9212011-02-23 18:56:55 +00001527#ifdef SK_DEBUG
1528void SkCanvas::validateClip() const {
1529 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001530 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001531 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001532 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001533 return;
1534 }
reed@google.com819c9212011-02-23 18:56:55 +00001535}
1536#endif
1537
Mike Reeda1361362017-03-07 09:37:29 -05001538bool SkCanvas::androidFramework_isClipAA() const {
1539 bool containsAA = false;
1540
1541 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1542
1543 return containsAA;
1544}
1545
1546class RgnAccumulator {
1547 SkRegion* fRgn;
1548public:
1549 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1550 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1551 SkIPoint origin = device->getOrigin();
1552 if (origin.x() | origin.y()) {
1553 rgn->translate(origin.x(), origin.y());
1554 }
1555 fRgn->op(*rgn, SkRegion::kUnion_Op);
1556 }
1557};
1558
1559void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1560 RgnAccumulator accum(rgn);
1561 SkRegion tmp;
1562
1563 rgn->setEmpty();
1564 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001565}
1566
reed@google.com5c3d1472011-02-22 19:12:23 +00001567///////////////////////////////////////////////////////////////////////////////
1568
reed@google.com754de5f2014-02-24 19:38:20 +00001569bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001570 return fMCRec->fRasterClip.isEmpty();
1571
1572 // TODO: should we only use the conservative answer in a recording canvas?
1573#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001574 SkBaseDevice* dev = this->getTopDevice();
1575 // if no device we return true
1576 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001577#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001578}
1579
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001580bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001581 SkBaseDevice* dev = this->getTopDevice();
1582 // if no device we return false
1583 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001584}
1585
msarettfbfa2582016-08-12 08:29:08 -07001586static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1587#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1588 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1589 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1590 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1591 return 0xF != _mm_movemask_ps(mask);
1592#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1593 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1594 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1595 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1596 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1597#else
1598 SkRect devRectAsRect;
1599 SkRect devClipAsRect;
1600 devRect.store(&devRectAsRect.fLeft);
1601 devClip.store(&devClipAsRect.fLeft);
1602 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1603#endif
1604}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001605
msarettfbfa2582016-08-12 08:29:08 -07001606// It's important for this function to not be inlined. Otherwise the compiler will share code
1607// between the fast path and the slow path, resulting in two slow paths.
1608static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1609 const SkMatrix& matrix) {
1610 SkRect deviceRect;
1611 matrix.mapRect(&deviceRect, src);
1612 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1613}
1614
1615bool SkCanvas::quickReject(const SkRect& src) const {
1616#ifdef SK_DEBUG
1617 // Verify that fDeviceClipBounds are set properly.
1618 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001619 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001620 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001621 } else {
msarettfbfa2582016-08-12 08:29:08 -07001622 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001623 }
msarettfbfa2582016-08-12 08:29:08 -07001624
msarett9637ea92016-08-18 14:03:30 -07001625 // Verify that fIsScaleTranslate is set properly.
1626 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001627#endif
1628
msarett9637ea92016-08-18 14:03:30 -07001629 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001630 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1631 }
1632
1633 // We inline the implementation of mapScaleTranslate() for the fast path.
1634 float sx = fMCRec->fMatrix.getScaleX();
1635 float sy = fMCRec->fMatrix.getScaleY();
1636 float tx = fMCRec->fMatrix.getTranslateX();
1637 float ty = fMCRec->fMatrix.getTranslateY();
1638 Sk4f scale(sx, sy, sx, sy);
1639 Sk4f trans(tx, ty, tx, ty);
1640
1641 // Apply matrix.
1642 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1643
1644 // Make sure left < right, top < bottom.
1645 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1646 Sk4f min = Sk4f::Min(ltrb, rblt);
1647 Sk4f max = Sk4f::Max(ltrb, rblt);
1648 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1649 // ARM this sequence generates the fastest (a single instruction).
1650 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1651
1652 // Check if the device rect is NaN or outside the clip.
1653 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001654}
1655
reed@google.com3b3e8952012-08-16 20:53:31 +00001656bool SkCanvas::quickReject(const SkPath& path) const {
1657 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658}
1659
Mike Klein83c8dd92017-11-28 17:08:45 -05001660SkRect SkCanvas::getLocalClipBounds() const {
1661 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001662 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001663 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664 }
1665
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001666 SkMatrix inverse;
1667 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001668 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001669 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001670 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001671
Mike Reed42e8c532017-01-23 14:09:13 -05001672 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001673 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001674 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001675
Mike Reedb57b9312018-04-23 12:12:54 -04001676 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001677 inverse.mapRect(&bounds, r);
1678 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001679}
1680
Mike Klein83c8dd92017-11-28 17:08:45 -05001681SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001682 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001683}
1684
reed@android.com8a1c16f2008-12-17 15:59:43 +00001685const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001686 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687}
1688
Brian Osman11052242016-10-27 14:47:55 -04001689GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001690 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001691 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001692}
1693
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001694GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001695 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001696 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001697}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001698
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001699void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1700 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001701 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001702 if (outer.isEmpty()) {
1703 return;
1704 }
1705 if (inner.isEmpty()) {
1706 this->drawRRect(outer, paint);
1707 return;
1708 }
1709
1710 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001711 // be able to return ...
1712 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001713 //
1714 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001715 if (!outer.getBounds().contains(inner.getBounds())) {
1716 return;
1717 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001718
1719 this->onDrawDRRect(outer, inner, paint);
1720}
1721
reed41af9662015-01-05 07:49:08 -08001722void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001723 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001724 this->onDrawPaint(paint);
1725}
1726
1727void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001728 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001729 // To avoid redundant logic in our culling code and various backends, we always sort rects
1730 // before passing them along.
1731 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001732}
1733
Mike Reedd5674082019-04-19 15:00:47 -04001734void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1735 TRACE_EVENT0("skia", TRACE_FUNC);
1736 this->onDrawBehind(paint);
1737}
1738
msarettdca352e2016-08-26 06:37:45 -07001739void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001740 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001741 if (region.isEmpty()) {
1742 return;
1743 }
1744
1745 if (region.isRect()) {
1746 return this->drawIRect(region.getBounds(), paint);
1747 }
1748
1749 this->onDrawRegion(region, paint);
1750}
1751
reed41af9662015-01-05 07:49:08 -08001752void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001753 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001754 // To avoid redundant logic in our culling code and various backends, we always sort rects
1755 // before passing them along.
1756 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001757}
1758
1759void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001760 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001761 this->onDrawRRect(rrect, paint);
1762}
1763
1764void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001765 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001766 this->onDrawPoints(mode, count, pts, paint);
1767}
1768
Mike Reede88a1cb2017-03-17 09:50:46 -04001769void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1770 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001771 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001772 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001773 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1774 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001775 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001776}
1777
1778void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001779 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001780 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001781 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1782}
1783
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001784void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1785 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001786 TRACE_EVENT0("skia", TRACE_FUNC);
1787 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001788 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001789 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1790}
1791
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001792void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1793 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001794 TRACE_EVENT0("skia", TRACE_FUNC);
1795 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001796 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001797 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001798}
1799
1800void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001801 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001802 this->onDrawPath(path, paint);
1803}
1804
reeda85d4d02015-05-06 12:56:48 -07001805void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001806 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001807 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001808 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001809}
1810
Mike Reedc4e31092018-01-30 11:15:27 -05001811// Returns true if the rect can be "filled" : non-empty and finite
1812static bool fillable(const SkRect& r) {
1813 SkScalar w = r.width();
1814 SkScalar h = r.height();
1815 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1816}
1817
reede47829b2015-08-06 10:02:53 -07001818void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1819 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001820 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001821 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001822 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001823 return;
1824 }
1825 this->onDrawImageRect(image, &src, dst, paint, constraint);
1826}
reed41af9662015-01-05 07:49:08 -08001827
reed84984ef2015-07-17 07:09:43 -07001828void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1829 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001830 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001831 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001832}
1833
Brian Salomonf08002c2018-10-26 16:15:46 -04001834void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001835 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001836 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001837 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001838}
reede47829b2015-08-06 10:02:53 -07001839
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001840namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001841class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001842public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001843 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1844 if (!origPaint) {
1845 return;
1846 }
1847 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1848 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1849 }
1850 if (origPaint->getMaskFilter()) {
1851 fPaint.writable()->setMaskFilter(nullptr);
1852 }
1853 if (origPaint->isAntiAlias()) {
1854 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001855 }
1856 }
1857
1858 const SkPaint* get() const {
1859 return fPaint;
1860 }
1861
1862private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001863 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001864};
1865} // namespace
1866
reed4c21dc52015-06-25 12:32:03 -07001867void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1868 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001869 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001870 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001871 if (dst.isEmpty()) {
1872 return;
1873 }
msarett552bca92016-08-03 06:53:26 -07001874 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001875 LatticePaint latticePaint(paint);
1876 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001877 } else {
reede47829b2015-08-06 10:02:53 -07001878 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001879 }
reed4c21dc52015-06-25 12:32:03 -07001880}
1881
msarett16882062016-08-16 09:31:08 -07001882void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1883 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001884 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001885 RETURN_ON_NULL(image);
1886 if (dst.isEmpty()) {
1887 return;
1888 }
msarett71df2d72016-09-30 12:41:42 -07001889
1890 SkIRect bounds;
1891 Lattice latticePlusBounds = lattice;
1892 if (!latticePlusBounds.fBounds) {
1893 bounds = SkIRect::MakeWH(image->width(), image->height());
1894 latticePlusBounds.fBounds = &bounds;
1895 }
1896
1897 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001898 LatticePaint latticePaint(paint);
1899 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001900 } else {
1901 this->drawImageRect(image, dst, paint);
1902 }
1903}
1904
reed41af9662015-01-05 07:49:08 -08001905void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001906 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001907 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001908 return;
1909 }
reed41af9662015-01-05 07:49:08 -08001910 this->onDrawBitmap(bitmap, dx, dy, paint);
1911}
1912
reede47829b2015-08-06 10:02:53 -07001913void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001914 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001915 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001916 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001917 return;
1918 }
reede47829b2015-08-06 10:02:53 -07001919 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001920}
1921
reed84984ef2015-07-17 07:09:43 -07001922void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1923 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001924 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001925}
1926
reede47829b2015-08-06 10:02:53 -07001927void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1928 SrcRectConstraint constraint) {
1929 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1930 constraint);
1931}
reede47829b2015-08-06 10:02:53 -07001932
reed41af9662015-01-05 07:49:08 -08001933void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1934 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001935 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001936 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001937 return;
1938 }
msarett552bca92016-08-03 06:53:26 -07001939 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001940 LatticePaint latticePaint(paint);
1941 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001942 } else {
reeda5517e22015-07-14 10:54:12 -07001943 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001944 }
reed41af9662015-01-05 07:49:08 -08001945}
1946
msarettc573a402016-08-02 08:05:56 -07001947void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1948 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001949 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001950 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001951 return;
1952 }
msarett71df2d72016-09-30 12:41:42 -07001953
1954 SkIRect bounds;
1955 Lattice latticePlusBounds = lattice;
1956 if (!latticePlusBounds.fBounds) {
1957 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1958 latticePlusBounds.fBounds = &bounds;
1959 }
1960
1961 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001962 LatticePaint latticePaint(paint);
1963 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001964 } else {
msarett16882062016-08-16 09:31:08 -07001965 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001966 }
msarettc573a402016-08-02 08:05:56 -07001967}
1968
reed71c3c762015-06-24 10:29:17 -07001969void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001970 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001971 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001972 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001973 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001974 if (count <= 0) {
1975 return;
1976 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001977 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001978 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001979 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001980}
1981
reedf70b5312016-03-04 16:36:20 -08001982void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001983 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001984 if (key) {
1985 this->onDrawAnnotation(rect, key, value);
1986 }
1987}
1988
reede47829b2015-08-06 10:02:53 -07001989void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1990 const SkPaint* paint, SrcRectConstraint constraint) {
1991 if (src) {
1992 this->drawImageRect(image, *src, dst, paint, constraint);
1993 } else {
1994 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1995 dst, paint, constraint);
1996 }
1997}
1998void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1999 const SkPaint* paint, SrcRectConstraint constraint) {
2000 if (src) {
2001 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2002 } else {
2003 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2004 dst, paint, constraint);
2005 }
2006}
2007
Mike Reed4204da22017-05-17 08:53:36 -04002008void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002009 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04002010 this->onDrawShadowRec(path, rec);
2011}
2012
2013void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
2014 SkPaint paint;
2015 const SkRect& pathBounds = path.getBounds();
2016
Ben Wagner2c312c42018-06-27 14:46:46 -04002017 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04002018 while (iter.next()) {
2019 iter.fDevice->drawShadow(path, rec);
2020 }
2021 LOOPER_END
2022}
2023
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002024void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2025 QuadAAFlags aaFlags, SkColor color, SkBlendMode mode) {
2026 TRACE_EVENT0("skia", TRACE_FUNC);
2027 // Make sure the rect is sorted before passing it along
2028 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2029}
2030
2031void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2032 const SkPoint dstClips[],
2033 const SkMatrix preViewMatrices[],
2034 const SkPaint* paint,
2035 SrcRectConstraint constraint) {
2036 TRACE_EVENT0("skia", TRACE_FUNC);
2037 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2038}
2039
reed@android.com8a1c16f2008-12-17 15:59:43 +00002040//////////////////////////////////////////////////////////////////////////////
2041// These are the virtual drawing methods
2042//////////////////////////////////////////////////////////////////////////////
2043
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002044void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002045 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002046 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2047 }
2048}
2049
reed41af9662015-01-05 07:49:08 -08002050void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002051 this->internalDrawPaint(paint);
2052}
2053
2054void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002055 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002056
2057 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002058 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002059 }
2060
reed@google.com4e2b3d32011-04-07 14:18:59 +00002061 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002062}
2063
reed41af9662015-01-05 07:49:08 -08002064void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2065 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002066 if ((long)count <= 0) {
2067 return;
2068 }
2069
Mike Reed822128b2017-02-28 16:41:03 -05002070 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002071 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002072 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002073 // special-case 2 points (common for drawing a single line)
2074 if (2 == count) {
2075 r.set(pts[0], pts[1]);
2076 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002077 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002078 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002079 if (!r.isFinite()) {
2080 return;
2081 }
Mike Reed822128b2017-02-28 16:41:03 -05002082 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002083 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2084 return;
2085 }
2086 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002087 }
reed@google.coma584aed2012-05-16 14:06:02 +00002088
halcanary96fcdcc2015-08-27 07:41:13 -07002089 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002090
Ben Wagner2c312c42018-06-27 14:46:46 -04002091 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002092
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002094 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002095 }
reed@google.com4b226022011-01-11 18:32:13 +00002096
reed@google.com4e2b3d32011-04-07 14:18:59 +00002097 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002098}
2099
reed4a167172016-08-18 17:15:25 -07002100static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2101 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07002102 (intptr_t)paint.getLooper() ) != 0;
2103}
2104
reed41af9662015-01-05 07:49:08 -08002105void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002106 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002107 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002108 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002109 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002110 return;
2111 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002112 }
reed@google.com4b226022011-01-11 18:32:13 +00002113
reed4a167172016-08-18 17:15:25 -07002114 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002115 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002116
reed4a167172016-08-18 17:15:25 -07002117 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002118 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002119 }
2120
2121 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002122 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002123 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002124 SkDrawIter iter(this);
2125 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002126 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002127 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002128 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002129}
2130
msarett44df6512016-08-25 13:54:30 -07002131void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002132 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002133 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002134 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002135 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2136 return;
2137 }
msarett44df6512016-08-25 13:54:30 -07002138 }
2139
Ben Wagner2c312c42018-06-27 14:46:46 -04002140 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002141
2142 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002143 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002144 }
2145
2146 LOOPER_END
2147}
2148
Mike Reedd5674082019-04-19 15:00:47 -04002149void SkCanvas::onDrawBehind(const SkPaint& paint) {
2150 SkIRect bounds;
2151 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2152 for (;;) {
2153 const MCRec* rec = (const MCRec*)iter.prev();
2154 if (!rec) {
2155 return; // no backimages, so nothing to draw
2156 }
2157 if (rec->fBackImage) {
2158 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2159 rec->fBackImage->fImage->width(),
2160 rec->fBackImage->fImage->height());
2161 break;
2162 }
2163 }
2164
2165 LOOPER_BEGIN(paint, nullptr)
2166
2167 while (iter.next()) {
2168 SkBaseDevice* dev = iter.fDevice;
2169
Mike Reedd5674082019-04-19 15:00:47 -04002170 dev->save();
2171 // We use clipRegion because it is already defined to operate in dev-space
2172 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2173 // but we don't want that, so we undo that before calling in.
2174 SkRegion rgn(bounds.makeOffset(dev->fOrigin.fX, dev->fOrigin.fY));
2175 dev->clipRegion(rgn, SkClipOp::kIntersect);
2176 dev->drawPaint(looper.paint());
Mike Reed9adc82c2019-04-23 10:28:13 -04002177 dev->restore(fMCRec->fMatrix);
Mike Reedd5674082019-04-19 15:00:47 -04002178 }
2179
2180 LOOPER_END
2181}
2182
reed41af9662015-01-05 07:49:08 -08002183void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002184 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002185 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002186 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002187 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002188 return;
2189 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002190 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002191
Ben Wagner2c312c42018-06-27 14:46:46 -04002192 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002193
2194 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002195 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002196 }
2197
2198 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002199}
2200
bsalomonac3aa242016-08-19 11:25:19 -07002201void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2202 SkScalar sweepAngle, bool useCenter,
2203 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002204 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002205 if (paint.canComputeFastBounds()) {
2206 SkRect storage;
2207 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002208 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002209 return;
2210 }
bsalomonac3aa242016-08-19 11:25:19 -07002211 }
2212
Ben Wagner2c312c42018-06-27 14:46:46 -04002213 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002214
2215 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002216 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002217 }
2218
2219 LOOPER_END
2220}
2221
reed41af9662015-01-05 07:49:08 -08002222void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002223 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002224 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002225 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2226 return;
2227 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002228 }
2229
2230 if (rrect.isRect()) {
2231 // call the non-virtual version
2232 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002233 return;
2234 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002235 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002236 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2237 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002238 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002239
Ben Wagner2c312c42018-06-27 14:46:46 -04002240 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002241
2242 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002243 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002244 }
2245
2246 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002247}
2248
Mike Reed822128b2017-02-28 16:41:03 -05002249void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002250 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002251 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002252 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2253 return;
2254 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002255 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002256
Ben Wagner2c312c42018-06-27 14:46:46 -04002257 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002258
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002259 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002260 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002261 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002262
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002263 LOOPER_END
2264}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002265
reed41af9662015-01-05 07:49:08 -08002266void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002267 if (!path.isFinite()) {
2268 return;
2269 }
2270
Mike Reed822128b2017-02-28 16:41:03 -05002271 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002272 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002273 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002274 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2275 return;
2276 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002277 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002278
Mike Reed822128b2017-02-28 16:41:03 -05002279 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002280 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002281 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002282 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002283 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002284 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002285
Ben Wagner2c312c42018-06-27 14:46:46 -04002286 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002287
2288 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002289 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290 }
2291
reed@google.com4e2b3d32011-04-07 14:18:59 +00002292 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002293}
2294
reed262a71b2015-12-05 13:07:27 -08002295bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002296 if (!paint.getImageFilter()) {
2297 return false;
2298 }
2299
2300 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002301 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002302 return false;
2303 }
2304
2305 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2306 // Once we can filter and the filter will return a result larger than itself, we should be
2307 // able to remove this constraint.
2308 // skbug.com/4526
2309 //
2310 SkPoint pt;
2311 ctm.mapXY(x, y, &pt);
2312 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2313 return ir.contains(fMCRec->fRasterClip.getBounds());
2314}
2315
Mike Reedf441cfc2018-04-11 14:50:16 -04002316// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2317// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2318// null.
2319static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2320 if (paintParam) {
2321 *real = *paintParam;
2322 real->setStyle(SkPaint::kFill_Style);
2323 real->setPathEffect(nullptr);
2324 paintParam = real;
2325 }
2326 return paintParam;
2327}
2328
reeda85d4d02015-05-06 12:56:48 -07002329void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002330 SkPaint realPaint;
2331 paint = init_image_paint(&realPaint, paint);
2332
reeda85d4d02015-05-06 12:56:48 -07002333 SkRect bounds = SkRect::MakeXYWH(x, y,
2334 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002335 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002336 SkRect tmp = bounds;
2337 if (paint) {
2338 paint->computeFastBounds(tmp, &tmp);
2339 }
2340 if (this->quickReject(tmp)) {
2341 return;
2342 }
reeda85d4d02015-05-06 12:56:48 -07002343 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002344 // At this point we need a real paint object. If the caller passed null, then we should
2345 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2346 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2347 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002348
reeda2217ef2016-07-20 06:04:34 -07002349 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002350 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2351 *paint);
2352 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002353 special = this->getDevice()->makeSpecial(image);
2354 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002355 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002356 }
2357 }
2358
reed262a71b2015-12-05 13:07:27 -08002359 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2360
reeda85d4d02015-05-06 12:56:48 -07002361 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002362 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002363 if (special) {
2364 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002365 iter.fDevice->ctm().mapXY(x, y, &pt);
2366 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002367 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002368 SkScalarRoundToInt(pt.fY), pnt,
2369 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002370 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002371 iter.fDevice->drawImageRect(
2372 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2373 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002374 }
reeda85d4d02015-05-06 12:56:48 -07002375 }
halcanary9d524f22016-03-29 09:03:52 -07002376
reeda85d4d02015-05-06 12:56:48 -07002377 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002378}
2379
reed41af9662015-01-05 07:49:08 -08002380void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002381 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002382 SkPaint realPaint;
2383 paint = init_image_paint(&realPaint, paint);
2384
halcanary96fcdcc2015-08-27 07:41:13 -07002385 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002386 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002387 if (paint) {
2388 paint->computeFastBounds(dst, &storage);
2389 }
2390 if (this->quickReject(storage)) {
2391 return;
2392 }
reeda85d4d02015-05-06 12:56:48 -07002393 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002394 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002395
Ben Wagner2c312c42018-06-27 14:46:46 -04002396 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002397
reeda85d4d02015-05-06 12:56:48 -07002398 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002399 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002400 }
halcanary9d524f22016-03-29 09:03:52 -07002401
reeda85d4d02015-05-06 12:56:48 -07002402 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002403}
2404
reed41af9662015-01-05 07:49:08 -08002405void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002406 SkDEBUGCODE(bitmap.validate();)
2407
reed33366972015-10-08 09:22:02 -07002408 if (bitmap.drawsNothing()) {
2409 return;
2410 }
2411
Mike Reedf441cfc2018-04-11 14:50:16 -04002412 SkPaint realPaint;
2413 init_image_paint(&realPaint, paint);
2414 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002415
Mike Reed822128b2017-02-28 16:41:03 -05002416 SkRect bounds;
2417 bitmap.getBounds(&bounds);
2418 bounds.offset(x, y);
2419 bool canFastBounds = paint->canComputeFastBounds();
2420 if (canFastBounds) {
2421 SkRect storage;
2422 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002423 return;
2424 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002425 }
reed@google.com4b226022011-01-11 18:32:13 +00002426
reeda2217ef2016-07-20 06:04:34 -07002427 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002428 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2429 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002430 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002431 special = this->getDevice()->makeSpecial(bitmap);
2432 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002433 drawAsSprite = false;
2434 }
2435 }
2436
Mike Reed822128b2017-02-28 16:41:03 -05002437 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002438
2439 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002440 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002441 if (special) {
reed262a71b2015-12-05 13:07:27 -08002442 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002443 iter.fDevice->ctm().mapXY(x, y, &pt);
2444 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002445 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002446 SkScalarRoundToInt(pt.fY), pnt,
2447 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002448 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002449 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2450 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2451 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002452 }
reed33366972015-10-08 09:22:02 -07002453 }
msarettfbfa2582016-08-12 08:29:08 -07002454
reed33366972015-10-08 09:22:02 -07002455 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002456}
2457
reed@google.com9987ec32011-09-07 11:57:52 +00002458// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002459void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002460 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002461 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002462 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002463 return;
2464 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002465
halcanary96fcdcc2015-08-27 07:41:13 -07002466 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002467 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002468 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2469 return;
2470 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002471 }
reed@google.com3d608122011-11-21 15:16:16 +00002472
reed@google.com33535f32012-09-25 15:37:50 +00002473 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002474 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002475 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002477
Ben Wagner2c312c42018-06-27 14:46:46 -04002478 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002479
reed@google.com33535f32012-09-25 15:37:50 +00002480 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002481 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002482 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002483
reed@google.com33535f32012-09-25 15:37:50 +00002484 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002485}
2486
reed41af9662015-01-05 07:49:08 -08002487void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002488 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002489 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002490 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002491}
2492
reed4c21dc52015-06-25 12:32:03 -07002493void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2494 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002495 SkPaint realPaint;
2496 paint = init_image_paint(&realPaint, paint);
2497
halcanary96fcdcc2015-08-27 07:41:13 -07002498 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002499 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002500 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2501 return;
2502 }
reed@google.com3d608122011-11-21 15:16:16 +00002503 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002504 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002505
Ben Wagner2c312c42018-06-27 14:46:46 -04002506 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002507
reed4c21dc52015-06-25 12:32:03 -07002508 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002509 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002510 }
halcanary9d524f22016-03-29 09:03:52 -07002511
reed4c21dc52015-06-25 12:32:03 -07002512 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002513}
2514
reed41af9662015-01-05 07:49:08 -08002515void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2516 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002517 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002518 SkPaint realPaint;
2519 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002520
halcanary96fcdcc2015-08-27 07:41:13 -07002521 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002522 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002523 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2524 return;
2525 }
reed4c21dc52015-06-25 12:32:03 -07002526 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002527 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002528
Ben Wagner2c312c42018-06-27 14:46:46 -04002529 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002530
reed4c21dc52015-06-25 12:32:03 -07002531 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002532 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002533 }
halcanary9d524f22016-03-29 09:03:52 -07002534
reed4c21dc52015-06-25 12:32:03 -07002535 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002536}
2537
msarett16882062016-08-16 09:31:08 -07002538void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2539 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002540 SkPaint realPaint;
2541 paint = init_image_paint(&realPaint, paint);
2542
msarett16882062016-08-16 09:31:08 -07002543 if (nullptr == paint || paint->canComputeFastBounds()) {
2544 SkRect storage;
2545 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2546 return;
2547 }
2548 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002549 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002550
Ben Wagner2c312c42018-06-27 14:46:46 -04002551 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002552
2553 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002554 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002555 }
2556
2557 LOOPER_END
2558}
2559
2560void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2561 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002562 SkPaint realPaint;
2563 paint = init_image_paint(&realPaint, paint);
2564
msarett16882062016-08-16 09:31:08 -07002565 if (nullptr == paint || paint->canComputeFastBounds()) {
2566 SkRect storage;
2567 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2568 return;
2569 }
2570 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002571 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002572
Ben Wagner2c312c42018-06-27 14:46:46 -04002573 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002574
2575 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002576 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002577 }
2578
2579 LOOPER_END
2580}
2581
fmalita00d5c2c2014-08-21 08:53:26 -07002582void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2583 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002584 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002585 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002586 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002587 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002588 SkRect tmp;
2589 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2590 return;
2591 }
2592 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002593 }
2594
fmalita024f9962015-03-03 19:08:17 -08002595 // We cannot filter in the looper as we normally do, because the paint is
2596 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002597 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002598
fmalitaaa1b9122014-08-28 14:32:24 -07002599 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002600 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002601 }
2602
fmalitaaa1b9122014-08-28 14:32:24 -07002603 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002604}
2605
Mike Reed358fcad2018-11-23 15:27:51 -05002606// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002607void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002608 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2609 TRACE_EVENT0("skia", TRACE_FUNC);
2610 if (byteLength) {
2611 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002612 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002613 }
2614}
Mike Reed4f81bb72019-01-23 09:23:00 -05002615
fmalita00d5c2c2014-08-21 08:53:26 -07002616void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2617 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002618 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002619 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002620 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002621 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002622}
reed@google.come0d9ce82014-04-23 04:00:17 +00002623
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002624void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002625 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002626 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002627
2628 while (iter.next()) {
2629 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002630 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002631 }
2632
2633 LOOPER_END
2634}
2635
dandovb3c9d1c2014-08-12 08:34:29 -07002636void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002637 const SkPoint texCoords[4], SkBlendMode bmode,
2638 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002639 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002640 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002641 return;
2642 }
mtklein6cfa73a2014-08-13 13:33:49 -07002643
Mike Reedfaba3712016-11-03 14:45:31 -04002644 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002645}
2646
2647void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002648 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002649 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002650 // Since a patch is always within the convex hull of the control points, we discard it when its
2651 // bounding rectangle is completely outside the current clip.
2652 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002653 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002654 if (this->quickReject(bounds)) {
2655 return;
2656 }
mtklein6cfa73a2014-08-13 13:33:49 -07002657
Ben Wagner2c312c42018-06-27 14:46:46 -04002658 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002659
dandovecfff212014-08-04 10:02:00 -07002660 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002661 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002662 }
mtklein6cfa73a2014-08-13 13:33:49 -07002663
dandovecfff212014-08-04 10:02:00 -07002664 LOOPER_END
2665}
2666
reeda8db7282015-07-07 10:22:31 -07002667void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002668#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002669 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002670#endif
reede3b38ce2016-01-08 09:18:44 -08002671 RETURN_ON_NULL(dr);
2672 if (x || y) {
2673 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2674 this->onDrawDrawable(dr, &matrix);
2675 } else {
2676 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002677 }
2678}
2679
reeda8db7282015-07-07 10:22:31 -07002680void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002681#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002682 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002683#endif
reede3b38ce2016-01-08 09:18:44 -08002684 RETURN_ON_NULL(dr);
2685 if (matrix && matrix->isIdentity()) {
2686 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002687 }
reede3b38ce2016-01-08 09:18:44 -08002688 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002689}
2690
2691void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002692 // drawable bounds are no longer reliable (e.g. android displaylist)
2693 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002694 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002695}
2696
reed71c3c762015-06-24 10:29:17 -07002697void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002698 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002699 const SkRect* cull, const SkPaint* paint) {
2700 if (cull && this->quickReject(*cull)) {
2701 return;
2702 }
2703
2704 SkPaint pnt;
2705 if (paint) {
2706 pnt = *paint;
2707 }
halcanary9d524f22016-03-29 09:03:52 -07002708
Ben Wagner2c312c42018-06-27 14:46:46 -04002709 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002710 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002711 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002712 }
2713 LOOPER_END
2714}
2715
reedf70b5312016-03-04 16:36:20 -08002716void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2717 SkASSERT(key);
2718
2719 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002720 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002721 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002722 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002723 }
2724 LOOPER_END
2725}
2726
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002727void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2728 SkColor color, SkBlendMode mode) {
2729 SkASSERT(r.isSorted());
2730
2731 // If this used a paint, it would be a filled color with blend mode, which does not
2732 // need to use an autodraw loop, so use SkDrawIter directly.
2733 if (this->quickReject(r)) {
2734 return;
2735 }
2736
2737 this->predrawNotify();
2738 SkDrawIter iter(this);
2739 while(iter.next()) {
2740 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2741 }
2742}
2743
2744void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2745 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2746 const SkPaint* paint, SrcRectConstraint constraint) {
2747 SkPaint realPaint;
2748 init_image_paint(&realPaint, paint);
2749
2750 // Looper is used when there are image filters, which drawEdgeAAImageSet needs to support
2751 // for Chromium's RenderPassDrawQuads' filters.
2752 LOOPER_BEGIN(realPaint, nullptr)
2753 while (iter.next()) {
2754 iter.fDevice->drawEdgeAAImageSet(
2755 imageSet, count, dstClips, preViewMatrices, looper.paint(), constraint);
2756 }
2757 LOOPER_END
2758}
2759
reed@android.com8a1c16f2008-12-17 15:59:43 +00002760//////////////////////////////////////////////////////////////////////////////
2761// These methods are NOT virtual, and therefore must call back into virtual
2762// methods, rather than actually drawing themselves.
2763//////////////////////////////////////////////////////////////////////////////
2764
reed374772b2016-10-05 17:33:02 -07002765void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002768 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769 this->drawPaint(paint);
2770}
2771
2772void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002773 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2775}
2776
Mike Reed3661bc92017-02-22 13:21:42 -05002777void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779 pts[0].set(x0, y0);
2780 pts[1].set(x1, y1);
2781 this->drawPoints(kLines_PointMode, 2, pts, paint);
2782}
2783
Mike Reed3661bc92017-02-22 13:21:42 -05002784void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002785 if (radius < 0) {
2786 radius = 0;
2787 }
2788
2789 SkRect r;
2790 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002791 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002792}
2793
2794void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2795 const SkPaint& paint) {
2796 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002797 SkRRect rrect;
2798 rrect.setRectXY(r, rx, ry);
2799 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002800 } else {
2801 this->drawRect(r, paint);
2802 }
2803}
2804
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2806 SkScalar sweepAngle, bool useCenter,
2807 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002808 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002809 if (oval.isEmpty() || !sweepAngle) {
2810 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002811 }
bsalomon21af9ca2016-08-25 12:29:23 -07002812 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002813}
2814
reed@android.comf76bacf2009-05-13 14:00:33 +00002815///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002816#ifdef SK_DISABLE_SKPICTURE
2817void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002818
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002819
2820void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2821 const SkPaint* paint) {}
2822#else
Mike Klein88d90712018-01-27 17:30:04 +00002823/**
2824 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2825 * against the playback cost of recursing into the subpicture to get at its actual ops.
2826 *
2827 * For now we pick a conservatively small value, though measurement (and other heuristics like
2828 * the type of ops contained) may justify changing this value.
2829 */
2830#define kMaxPictureOpsToUnrollInsteadOfRef 1
2831
reedd5fa1a42014-08-09 11:08:05 -07002832void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002833 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002834 RETURN_ON_NULL(picture);
2835
reede3b38ce2016-01-08 09:18:44 -08002836 if (matrix && matrix->isIdentity()) {
2837 matrix = nullptr;
2838 }
Mike Klein88d90712018-01-27 17:30:04 +00002839 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2840 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2841 picture->playback(this);
2842 } else {
2843 this->onDrawPicture(picture, matrix, paint);
2844 }
reedd5fa1a42014-08-09 11:08:05 -07002845}
robertphillips9b14f262014-06-04 05:40:44 -07002846
reedd5fa1a42014-08-09 11:08:05 -07002847void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2848 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002849 if (!paint || paint->canComputeFastBounds()) {
2850 SkRect bounds = picture->cullRect();
2851 if (paint) {
2852 paint->computeFastBounds(bounds, &bounds);
2853 }
2854 if (matrix) {
2855 matrix->mapRect(&bounds);
2856 }
2857 if (this->quickReject(bounds)) {
2858 return;
2859 }
2860 }
2861
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002862 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002863 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002864}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002865#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002866
reed@android.com8a1c16f2008-12-17 15:59:43 +00002867///////////////////////////////////////////////////////////////////////////////
2868///////////////////////////////////////////////////////////////////////////////
2869
reed3aafe112016-08-18 12:45:34 -07002870SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002871 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002872
2873 SkASSERT(canvas);
2874
reed3aafe112016-08-18 12:45:34 -07002875 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002876 fDone = !fImpl->next();
2877}
2878
2879SkCanvas::LayerIter::~LayerIter() {
2880 fImpl->~SkDrawIter();
2881}
2882
2883void SkCanvas::LayerIter::next() {
2884 fDone = !fImpl->next();
2885}
2886
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002887SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002888 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002889}
2890
2891const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002892 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002893}
2894
2895const SkPaint& SkCanvas::LayerIter::paint() const {
2896 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002897 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002898 paint = &fDefaultPaint;
2899 }
2900 return *paint;
2901}
2902
Mike Reedca37f322018-03-08 13:22:16 -05002903SkIRect SkCanvas::LayerIter::clipBounds() const {
2904 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002905}
2906
reed@android.com8a1c16f2008-12-17 15:59:43 +00002907int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2908int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002909
2910///////////////////////////////////////////////////////////////////////////////
2911
Brian Osmane8a98632019-04-10 10:26:10 -04002912SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2913SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2914SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2915SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2916
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002917SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2918 const SkRect& dstRect, int matrixIndex, float alpha,
2919 unsigned aaFlags, bool hasClip)
2920 : fImage(std::move(image))
2921 , fSrcRect(srcRect)
2922 , fDstRect(dstRect)
2923 , fMatrixIndex(matrixIndex)
2924 , fAlpha(alpha)
2925 , fAAFlags(aaFlags)
2926 , fHasClip(hasClip) {}
2927
2928SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2929 const SkRect& dstRect, float alpha, unsigned aaFlags)
2930 : fImage(std::move(image))
2931 , fSrcRect(srcRect)
2932 , fDstRect(dstRect)
2933 , fAlpha(alpha)
2934 , fAAFlags(aaFlags) {}
2935
2936///////////////////////////////////////////////////////////////////////////////
2937
Mike Reed5df49342016-11-12 08:06:55 -06002938std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002939 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002940 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002941 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002942 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002943
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002944 SkBitmap bitmap;
2945 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002946 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002947 }
Mike Reed12f77342017-11-08 11:19:52 -05002948
2949 return props ?
2950 skstd::make_unique<SkCanvas>(bitmap, *props) :
2951 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002952}
reedd5fa1a42014-08-09 11:08:05 -07002953
2954///////////////////////////////////////////////////////////////////////////////
2955
Florin Malitaee424ac2016-12-01 12:47:59 -05002956SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002957 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002958
Florin Malita439ace92016-12-02 12:05:41 -05002959SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002960 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002961
Herb Derbyefe39bc2018-05-01 17:06:20 -04002962SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002963 : INHERITED(device) {}
2964
Florin Malitaee424ac2016-12-01 12:47:59 -05002965SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2966 (void)this->INHERITED::getSaveLayerStrategy(rec);
2967 return kNoLayer_SaveLayerStrategy;
2968}
2969
Mike Reed148b7fd2018-12-18 17:38:18 -05002970bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2971 return false;
2972}
2973
Florin Malitaee424ac2016-12-01 12:47:59 -05002974///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002975
reed73603f32016-09-20 08:42:38 -07002976static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2977static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2978static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2979static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2980static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2981static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002982
2983///////////////////////////////////////////////////////////////////////////////////////////////////
2984
2985SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2986 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002987 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002988 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2989 SkIPoint origin = dev->getOrigin();
2990 SkMatrix ctm = this->getTotalMatrix();
2991 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2992
2993 SkIRect clip = fMCRec->fRasterClip.getBounds();
2994 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002995 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002996 clip.setEmpty();
2997 }
2998
2999 fAllocator->updateHandle(handle, ctm, clip);
3000 return handle;
3001 }
3002 return nullptr;
3003}
3004
3005static bool install(SkBitmap* bm, const SkImageInfo& info,
3006 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04003007 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05003008}
3009
3010SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3011 SkBitmap* bm) {
3012 SkRasterHandleAllocator::Rec rec;
3013 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3014 return nullptr;
3015 }
3016 return rec.fHandle;
3017}
3018
3019std::unique_ptr<SkCanvas>
3020SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3021 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04003022 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05003023 return nullptr;
3024 }
3025
3026 SkBitmap bm;
3027 Handle hndl;
3028
3029 if (rec) {
3030 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3031 } else {
3032 hndl = alloc->allocBitmap(info, &bm);
3033 }
3034 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3035}
Mike Reed7c9c9e42018-01-03 09:23:34 -05003036
3037///////////////////////////////////////////////////////////////////////////////////////////////////
3038
3039