blob: 4d0c7160bad581e27d180ea2c0290e005c93897e [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkCanvas.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkColorFilter.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkImage.h"
12#include "include/core/SkImageFilter.h"
13#include "include/core/SkPathEffect.h"
14#include "include/core/SkPicture.h"
15#include "include/core/SkRRect.h"
16#include "include/core/SkRasterHandleAllocator.h"
17#include "include/core/SkString.h"
18#include "include/core/SkTextBlob.h"
19#include "include/core/SkVertices.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "include/private/SkNx.h"
21#include "include/private/SkTo.h"
22#include "include/utils/SkNoDrawCanvas.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040023#include "src/core/SkArenaAlloc.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/core/SkBitmapDevice.h"
25#include "src/core/SkCanvasPriv.h"
26#include "src/core/SkClipOpPriv.h"
27#include "src/core/SkClipStack.h"
28#include "src/core/SkDraw.h"
29#include "src/core/SkGlyphRun.h"
30#include "src/core/SkImageFilterCache.h"
Michael Ludwig08b260c2019-05-17 11:21:53 -040031#include "src/core/SkImageFilterPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050032#include "src/core/SkLatticeIter.h"
33#include "src/core/SkMSAN.h"
34#include "src/core/SkMakeUnique.h"
35#include "src/core/SkMatrixUtils.h"
36#include "src/core/SkPaintPriv.h"
37#include "src/core/SkRasterClip.h"
38#include "src/core/SkSpecialImage.h"
39#include "src/core/SkStrikeCache.h"
40#include "src/core/SkTLazy.h"
41#include "src/core/SkTextFormatParams.h"
42#include "src/core/SkTraceEvent.h"
43#include "src/image/SkImage_Base.h"
44#include "src/image/SkSurface_Base.h"
45#include "src/utils/SkPatchUtils.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040046
bungemand3ebb482015-08-05 13:57:49 -070047#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000048
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000049#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050050#include "include/gpu/GrContext.h"
51#include "src/gpu/SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052#endif
53
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050055#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080056
Mike Reed139e5e02017-03-08 11:29:33 -050057///////////////////////////////////////////////////////////////////////////////////////////////////
58
reedc83a2972015-07-16 07:40:45 -070059/*
60 * Return true if the drawing this rect would hit every pixels in the canvas.
61 *
62 * Returns false if
63 * - rect does not contain the canvas' bounds
64 * - paint is not fill
65 * - paint would blur or otherwise change the coverage of the rect
66 */
67bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
68 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070069 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
70 (int)kNone_ShaderOverrideOpacity,
71 "need_matching_enums0");
72 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
73 (int)kOpaque_ShaderOverrideOpacity,
74 "need_matching_enums1");
75 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
76 (int)kNotOpaque_ShaderOverrideOpacity,
77 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070078
79 const SkISize size = this->getBaseLayerSize();
80 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050081
82 // if we're clipped at all, we can't overwrite the entire surface
83 {
84 SkBaseDevice* base = this->getDevice();
85 SkBaseDevice* top = this->getTopDevice();
86 if (base != top) {
87 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
88 }
89 if (!base->clipIsWideOpen()) {
90 return false;
91 }
reedc83a2972015-07-16 07:40:45 -070092 }
93
94 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070095 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070096 return false; // conservative
97 }
halcanaryc5769b22016-08-10 07:13:21 -070098
99 SkRect devRect;
100 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
101 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700102 return false;
103 }
104 }
105
106 if (paint) {
107 SkPaint::Style paintStyle = paint->getStyle();
108 if (!(paintStyle == SkPaint::kFill_Style ||
109 paintStyle == SkPaint::kStrokeAndFill_Style)) {
110 return false;
111 }
Mike Reed9dc0b9e2019-07-29 17:52:48 -0400112 if (paint->getMaskFilter() || paint->getPathEffect() || paint->getImageFilter()) {
reedc83a2972015-07-16 07:40:45 -0700113 return false; // conservative
114 }
115 }
116 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
117}
118
119///////////////////////////////////////////////////////////////////////////////////////////////////
120
reed@google.comda17f752012-08-16 18:27:05 +0000121// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122//#define SK_TRACE_SAVERESTORE
123
124#ifdef SK_TRACE_SAVERESTORE
125 static int gLayerCounter;
126 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
127 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
128
129 static int gRecCounter;
130 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
131 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
132
133 static int gCanvasCounter;
134 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
135 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
136#else
137 #define inc_layer()
138 #define dec_layer()
139 #define inc_rec()
140 #define dec_rec()
141 #define inc_canvas()
142 #define dec_canvas()
143#endif
144
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000145typedef SkTLazy<SkPaint> SkLazyPaint;
146
reedc83a2972015-07-16 07:40:45 -0700147void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000148 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700149 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
150 ? SkSurface::kDiscard_ContentChangeMode
151 : SkSurface::kRetain_ContentChangeMode);
152 }
153}
154
155void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
156 ShaderOverrideOpacity overrideOpacity) {
157 if (fSurfaceBase) {
158 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
159 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
160 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
161 // and therefore we don't care which mode we're in.
162 //
163 if (fSurfaceBase->outstandingImageSnapshot()) {
164 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
165 mode = SkSurface::kDiscard_ContentChangeMode;
166 }
167 }
168 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000169 }
170}
171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000174/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 The clip/matrix/proc are fields that reflect the top of the save/restore
176 stack. Whenever the canvas changes, it marks a dirty flag, and then before
177 these are used (assuming we're not on a layer) we rebuild these cache
178 values: they reflect the top of the save stack, but translated and clipped
179 by the device's XY offset and bitmap-bounds.
180*/
181struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400182 DeviceCM* fNext;
183 sk_sp<SkBaseDevice> fDevice;
184 SkRasterClip fClip;
185 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
186 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400187 sk_sp<SkImage> fClipImage;
188 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189
Florin Malita53f77bd2017-04-28 13:48:37 -0400190 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000191 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700192 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400193 , fDevice(std::move(device))
194 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700195 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000196 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400197 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400198 {}
reed@google.com4b226022011-01-11 18:32:13 +0000199
mtkleinfeaadee2015-04-08 11:25:48 -0700200 void reset(const SkIRect& bounds) {
201 SkASSERT(!fPaint);
202 SkASSERT(!fNext);
203 SkASSERT(fDevice);
204 fClip.setRect(bounds);
205 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206};
207
Mike Reed148b7fd2018-12-18 17:38:18 -0500208namespace {
209// Encapsulate state needed to restore from saveBehind()
210struct BackImage {
211 sk_sp<SkSpecialImage> fImage;
212 SkIPoint fLoc;
213};
214}
215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216/* This is the record we keep for each save/restore level in the stack.
217 Since a level optionally copies the matrix and/or stack, we have pointers
218 for these fields. If the value is copied for this level, the copy is
219 stored in the ...Storage field, and the pointer points to that. If the
220 value is not copied for this level, we ignore ...Storage, and just point
221 at the corresponding value in the previous level in the stack.
222*/
223class SkCanvas::MCRec {
224public:
Mike Reed148b7fd2018-12-18 17:38:18 -0500225 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 /* If there are any layers in the stack, this points to the top-most
227 one that is at or below this level in the stack (so we know what
228 bitmap/device to draw into from this level. This value is NOT
229 reference counted, since the real owner is either our fLayer field,
230 or a previous one in a lower level.)
231 */
Mike Reed148b7fd2018-12-18 17:38:18 -0500232 DeviceCM* fTopLayer;
233 std::unique_ptr<BackImage> fBackImage;
234 SkConservativeClip fRasterClip;
235 SkMatrix fMatrix;
236 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
Mike Reeda1361362017-03-07 09:37:29 -0500238 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700239 fLayer = nullptr;
240 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800241 fMatrix.reset();
242 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700243
reedd9544982014-09-09 18:46:22 -0700244 // don't bother initializing fNext
245 inc_rec();
246 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400247 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700248 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700249 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800250 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700251
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 // don't bother initializing fNext
253 inc_rec();
254 }
255 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700256 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 dec_rec();
258 }
mtkleinfeaadee2015-04-08 11:25:48 -0700259
260 void reset(const SkIRect& bounds) {
261 SkASSERT(fLayer);
262 SkASSERT(fDeferredSaveCount == 0);
263
264 fMatrix.reset();
265 fRasterClip.setRect(bounds);
266 fLayer->reset(bounds);
267 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268};
269
Mike Reeda1361362017-03-07 09:37:29 -0500270class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271public:
Mike Reeda1361362017-03-07 09:37:29 -0500272 SkDrawIter(SkCanvas* canvas)
273 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
274 {}
reed@google.com4b226022011-01-11 18:32:13 +0000275
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000277 const DeviceCM* rec = fCurrLayer;
278 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400279 fDevice = rec->fDevice.get();
280 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700282 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 return true;
284 }
285 return false;
286 }
reed@google.com4b226022011-01-11 18:32:13 +0000287
reed@google.com6f8f2922011-03-04 22:27:10 +0000288 int getX() const { return fDevice->getOrigin().x(); }
289 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000291
Mike Reed99330ba2017-02-22 11:01:08 -0500292 SkBaseDevice* fDevice;
293
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 const DeviceCM* fCurrLayer;
296 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297};
298
Florin Malita713b8ef2017-04-28 10:57:24 -0400299#define FOR_EACH_TOP_DEVICE( code ) \
300 do { \
301 DeviceCM* layer = fMCRec->fTopLayer; \
302 while (layer) { \
303 SkBaseDevice* device = layer->fDevice.get(); \
304 if (device) { \
305 code; \
306 } \
307 layer = layer->fNext; \
308 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500309 } while (0)
310
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311/////////////////////////////////////////////////////////////////////////////
312
reeddbc3cef2015-04-29 12:18:57 -0700313static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
314 return lazy->isValid() ? lazy->get() : lazy->set(orig);
315}
316
317/**
318 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700319 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700320 */
reedd053ce92016-03-22 10:17:23 -0700321static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700322 SkImageFilter* imgf = paint.getImageFilter();
323 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700324 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700325 }
326
reedd053ce92016-03-22 10:17:23 -0700327 SkColorFilter* imgCFPtr;
328 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700329 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700330 }
reedd053ce92016-03-22 10:17:23 -0700331 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700332
333 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700334 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700335 // there is no existing paint colorfilter, so we can just return the imagefilter's
336 return imgCF;
337 }
338
339 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
340 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500341 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700342}
343
senorblanco87e066e2015-10-28 11:23:36 -0700344/**
345 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
346 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
347 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
348 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
349 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
350 * conservative "effective" bounds based on the settings in the paint... with one exception. This
351 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
352 * deliberately ignored.
353 */
354static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
355 const SkRect& rawBounds,
356 SkRect* storage) {
357 SkPaint tmpUnfiltered(paint);
358 tmpUnfiltered.setImageFilter(nullptr);
359 if (tmpUnfiltered.canComputeFastBounds()) {
360 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
361 } else {
362 return rawBounds;
363 }
364}
365
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366class AutoDrawLooper {
367public:
senorblanco87e066e2015-10-28 11:23:36 -0700368 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
369 // paint. It's used to determine the size of the offscreen layer for filters.
370 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700371 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700372 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000373 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700374 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000375 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700376 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000377 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378
reedd053ce92016-03-22 10:17:23 -0700379 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700380 if (simplifiedCF) {
381 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700382 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700383 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700384 fPaint = paint;
385 }
386
387 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700388 /**
389 * We implement ImageFilters for a given draw by creating a layer, then applying the
390 * imagefilter to the pixels of that layer (its backing surface/image), and then
391 * we call restore() to xfer that layer to the main canvas.
392 *
393 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
394 * 2. Generate the src pixels:
395 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
396 * return (fPaint). We then draw the primitive (using srcover) into a cleared
397 * buffer/surface.
398 * 3. Restore the layer created in #1
399 * The imagefilter is passed the buffer/surface from the layer (now filled with the
400 * src pixels of the primitive). It returns a new "filtered" buffer, which we
401 * draw onto the previous layer using the xfermode from the original paint.
402 */
reed@google.com8926b162012-03-23 15:36:36 +0000403 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500404 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700405 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700406 SkRect storage;
407 if (rawBounds) {
408 // Make rawBounds include all paint outsets except for those due to image filters.
409 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
410 }
reedbfd5f172016-01-07 11:28:08 -0800411 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700412 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700413 fTempLayerForImageFilter = true;
414 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000415 }
416
Mike Reedb7dad442019-07-22 14:51:10 -0400417 {
Ben Wagner2c312c42018-06-27 14:46:46 -0400418 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000419 }
420 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000421
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700423 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000424 fCanvas->internalRestore();
425 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000426 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000428
reed@google.com4e2b3d32011-04-07 14:18:59 +0000429 const SkPaint& paint() const {
430 SkASSERT(fPaint);
431 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000433
Ben Wagner2c312c42018-06-27 14:46:46 -0400434 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000435 if (fDone) {
436 return false;
437 } else if (fIsSimple) {
438 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000439 return !fPaint->nothingToDraw();
440 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400441 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000442 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000443 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000444
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500446 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700447 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000448 SkCanvas* fCanvas;
449 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000450 const SkPaint* fPaint;
451 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700452 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000453 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000454 bool fIsSimple;
455
Ben Wagner2c312c42018-06-27 14:46:46 -0400456 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000457};
458
Ben Wagner2c312c42018-06-27 14:46:46 -0400459bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700460 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000461 SkASSERT(!fIsSimple);
Mike Reed9dc0b9e2019-07-29 17:52:48 -0400462 SkASSERT(fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000463
reeddbc3cef2015-04-29 12:18:57 -0700464 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
465 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000466
reed5c476fb2015-04-20 08:04:21 -0700467 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700468 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700469 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000470 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000471
reed@google.com129ec222012-05-15 13:24:09 +0000472 fPaint = paint;
473
474 // if we only came in here for the imagefilter, mark us as done
Mike Reed9dc0b9e2019-07-29 17:52:48 -0400475 fDone = true;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000476 return true;
477}
478
reed@android.com8a1c16f2008-12-17 15:59:43 +0000479////////// macros to place around the internal draw calls //////////////////
480
reed3aafe112016-08-18 12:45:34 -0700481#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
482 this->predrawNotify(); \
483 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400484 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800485 SkDrawIter iter(this);
486
487
Ben Wagner2c312c42018-06-27 14:46:46 -0400488#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000489 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700490 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400491 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000492 SkDrawIter iter(this);
493
Ben Wagner2c312c42018-06-27 14:46:46 -0400494#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000495 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700496 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400497 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000499
Ben Wagner2c312c42018-06-27 14:46:46 -0400500#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700501 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700502 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400503 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700504 SkDrawIter iter(this);
505
reed@google.com4e2b3d32011-04-07 14:18:59 +0000506#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000507
508////////////////////////////////////////////////////////////////////////////
509
msarettfbfa2582016-08-12 08:29:08 -0700510static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
511 if (bounds.isEmpty()) {
512 return SkRect::MakeEmpty();
513 }
514
515 // Expand bounds out by 1 in case we are anti-aliasing. We store the
516 // bounds as floats to enable a faster quick reject implementation.
517 SkRect dst;
518 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
519 return dst;
520}
521
mtkleinfeaadee2015-04-08 11:25:48 -0700522void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
523 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700524 fMCRec->reset(bounds);
525
526 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500527 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400528 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700529 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700530 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700531}
532
Hal Canary363a3f82018-10-04 11:04:48 -0400533void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000534 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800535 fSaveCount = 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536
537 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500538 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500539 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700540 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000541
reeda499f902015-05-01 09:34:31 -0700542 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
543 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400544 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700545
reed@android.com8a1c16f2008-12-17 15:59:43 +0000546 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000547
halcanary96fcdcc2015-08-27 07:41:13 -0700548 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000549
reedf92c8662014-08-18 08:02:43 -0700550 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700551 // The root device and the canvas should always have the same pixel geometry
552 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800553 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700554 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500555
Mike Reedc42a1cd2017-02-14 14:25:14 -0500556 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700557 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400558
Herb Derby59d997a2018-06-07 12:44:09 -0400559 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560}
561
reed@google.comcde92112011-07-06 20:00:52 +0000562SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000563 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700564 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000565{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000566 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000567
Hal Canary363a3f82018-10-04 11:04:48 -0400568 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000569}
570
reed96a857e2015-01-25 10:33:58 -0800571SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000572 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800573 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000574{
575 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400576 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400577 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700578}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000579
Hal Canary363a3f82018-10-04 11:04:48 -0400580SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700581 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700582 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700583{
584 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700585
Mike Reed566e53c2017-03-10 10:49:45 -0500586 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400587 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700588}
589
Herb Derbyefe39bc2018-05-01 17:06:20 -0400590SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000591 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700592 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000593{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000594 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700595
Hal Canary363a3f82018-10-04 11:04:48 -0400596 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700597}
598
reed4a8126e2014-09-22 07:29:03 -0700599SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700600 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700601 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700602{
603 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700604
Mike Reed910ca0f2018-04-25 13:04:05 -0400605 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400606 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700607}
reed29c857d2014-09-21 10:25:07 -0700608
Mike Reed356f7c22017-01-10 11:58:39 -0500609SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
610 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700611 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
612 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500613 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700614{
615 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700616
Mike Reed910ca0f2018-04-25 13:04:05 -0400617 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400618 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619}
620
Mike Reed356f7c22017-01-10 11:58:39 -0500621SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
622
Matt Sarett31f99ce2017-04-11 08:46:01 -0400623#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
624SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
625 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
626 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
627 , fAllocator(nullptr)
628{
629 inc_canvas();
630
631 SkBitmap tmp(bitmap);
632 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400633 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400634 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400635}
636#endif
637
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638SkCanvas::~SkCanvas() {
639 // free up the contents of our deque
640 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000641
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642 this->internalRestore(); // restore the last, since we're going away
643
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644 dec_canvas();
645}
646
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647///////////////////////////////////////////////////////////////////////////////
648
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000649void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700650 this->onFlush();
651}
652
653void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000654 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000655 if (device) {
656 device->flush();
657 }
658}
659
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000660SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000661 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000662 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
663}
664
senorblancoafc7cce2016-02-02 18:44:15 -0800665SkIRect SkCanvas::getTopLayerBounds() const {
666 SkBaseDevice* d = this->getTopDevice();
667 if (!d) {
668 return SkIRect::MakeEmpty();
669 }
670 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
671}
672
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000673SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000675 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000676 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400677 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678}
679
Florin Malita0ed3b642017-01-13 16:56:38 +0000680SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400681 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000682}
683
Mike Reed353196f2017-07-21 11:01:18 -0400684bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000685 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400686 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000687}
688
Mike Reed353196f2017-07-21 11:01:18 -0400689bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
690 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400691}
692
693bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
694 SkPixmap pm;
695 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
696}
697
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000698bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400699 SkPixmap pm;
700 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700701 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000702 }
703 return false;
704}
705
Matt Sarett03dd6d52017-01-23 12:15:09 -0500706bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000707 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000708 SkBaseDevice* device = this->getDevice();
709 if (!device) {
710 return false;
711 }
712
Matt Sarett03dd6d52017-01-23 12:15:09 -0500713 // This check gives us an early out and prevents generation ID churn on the surface.
714 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
715 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
716 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
717 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000718 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000719
Matt Sarett03dd6d52017-01-23 12:15:09 -0500720 // Tell our owning surface to bump its generation ID.
721 const bool completeOverwrite =
722 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700723 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700724
Matt Sarett03dd6d52017-01-23 12:15:09 -0500725 // This can still fail, most notably in the case of a invalid color type or alpha type
726 // conversion. We could pull those checks into this function and avoid the unnecessary
727 // generation ID bump. But then we would be performing those checks twice, since they
728 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400729 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000730}
reed@google.com51df9e32010-12-23 19:29:18 +0000731
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732//////////////////////////////////////////////////////////////////////////////
733
reed2ff1fce2014-12-11 07:07:37 -0800734void SkCanvas::checkForDeferredSave() {
735 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800736 this->doSave();
737 }
738}
739
reedf0090cb2014-11-26 08:55:51 -0800740int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800741#ifdef SK_DEBUG
742 int count = 0;
743 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
744 for (;;) {
745 const MCRec* rec = (const MCRec*)iter.next();
746 if (!rec) {
747 break;
748 }
749 count += 1 + rec->fDeferredSaveCount;
750 }
751 SkASSERT(count == fSaveCount);
752#endif
753 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800754}
755
756int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800757 fSaveCount += 1;
758 fMCRec->fDeferredSaveCount += 1;
759 return this->getSaveCount() - 1; // return our prev value
760}
761
762void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800763 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700764
765 SkASSERT(fMCRec->fDeferredSaveCount > 0);
766 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800767 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800768}
769
770void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800771 if (fMCRec->fDeferredSaveCount > 0) {
772 SkASSERT(fSaveCount > 1);
773 fSaveCount -= 1;
774 fMCRec->fDeferredSaveCount -= 1;
775 } else {
776 // check for underflow
777 if (fMCStack.count() > 1) {
778 this->willRestore();
779 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700780 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800781 this->internalRestore();
782 this->didRestore();
783 }
reedf0090cb2014-11-26 08:55:51 -0800784 }
785}
786
787void SkCanvas::restoreToCount(int count) {
788 // sanity check
789 if (count < 1) {
790 count = 1;
791 }
mtkleinf0f14112014-12-12 08:46:25 -0800792
reedf0090cb2014-11-26 08:55:51 -0800793 int n = this->getSaveCount() - count;
794 for (int i = 0; i < n; ++i) {
795 this->restore();
796 }
797}
798
reed2ff1fce2014-12-11 07:07:37 -0800799void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000800 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700801 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000802 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000803
Mike Reedc42a1cd2017-02-14 14:25:14 -0500804 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805}
806
reed4960eee2015-12-18 07:09:18 -0800807bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400808 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809}
810
reed4960eee2015-12-18 07:09:18 -0800811bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700812 SkIRect* intersection, const SkImageFilter* imageFilter) {
Michael Ludwigaa861a12019-07-19 10:13:47 -0400813 // clipRectBounds() is called to determine the input layer size needed for a given image filter.
814 // The coordinate space of the rectangle passed to filterBounds(kReverse) is meant to be in the
815 // filtering layer space. Here, 'clipBounds' is always in the true device space. When an image
816 // filter does not require a decomposed CTM matrix, the filter space and device space are the
817 // same. When it has been decomposed, we want the original image filter node to process the
818 // bounds in the layer space represented by the decomposed scale matrix. 'imageFilter' is no
819 // longer the original filter, but has the remainder matrix baked into it, and passing in the
820 // the true device clip bounds ensures that the matrix image filter provides a layer clip bounds
821 // to the original filter node (barring inflation from consecutive calls to mapRect). While
822 // initially counter-intuitive given the apparent inconsistency of coordinate spaces, always
823 // passing getDeviceClipBounds() to 'imageFilter' is correct.
824 // FIXME (michaelludwig) - When the remainder matrix is instead applied as a final draw, it will
825 // be important to more accurately calculate the clip bounds in the layer space for the original
826 // image filter (similar to how matrix image filter does it, but ideally without the inflation).
Mike Reed918e1442017-01-23 11:39:45 -0500827 SkIRect clipBounds = this->getDeviceClipBounds();
828 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000829 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000830 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000831
reed96e657d2015-03-10 17:30:07 -0700832 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
833
Robert Phillips12078432018-05-17 11:17:39 -0400834 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
835 // If the image filter DAG affects transparent black then we will need to render
836 // out to the clip bounds
837 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000838 }
Robert Phillips12078432018-05-17 11:17:39 -0400839
840 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700841 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000842 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700843 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400844 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400846 inputSaveLayerBounds = clipBounds;
847 }
848
849 if (imageFilter) {
850 // expand the clip bounds by the image filter DAG to include extra content that might
851 // be required by the image filters.
852 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
853 SkImageFilter::kReverse_MapDirection,
854 &inputSaveLayerBounds);
855 }
856
857 SkIRect clippedSaveLayerBounds;
858 if (bounds) {
859 // For better or for worse, user bounds currently act as a hard clip on the layer's
860 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
861 clippedSaveLayerBounds = inputSaveLayerBounds;
862 } else {
863 // If there are no user bounds, we don't want to artificially restrict the resulting
864 // layer bounds, so allow the expanded clip bounds free reign.
865 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000866 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800867
868 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400869 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800870 if (BoundsAffectsClip(saveLayerFlags)) {
871 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
872 fMCRec->fRasterClip.setEmpty();
873 fDeviceClipBounds.setEmpty();
874 }
875 return false;
876 }
Robert Phillips12078432018-05-17 11:17:39 -0400877 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000878
reed4960eee2015-12-18 07:09:18 -0800879 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700880 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400881 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
882 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000883 }
884
885 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400886 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000887 }
Robert Phillips12078432018-05-17 11:17:39 -0400888
junov@chromium.orga907ac32012-02-24 21:54:07 +0000889 return true;
890}
891
reed4960eee2015-12-18 07:09:18 -0800892int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
893 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000894}
895
Cary Clarke041e312018-03-06 13:00:52 -0500896int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700897 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400898 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
899 // no need for the layer (or any of the draws until the matching restore()
900 this->save();
901 this->clipRect({0,0,0,0});
902 } else {
903 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
904 fSaveCount += 1;
905 this->internalSaveLayer(rec, strategy);
906 }
reed4960eee2015-12-18 07:09:18 -0800907 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800908}
909
Mike Reed148b7fd2018-12-18 17:38:18 -0500910int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
911 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
912 // Assuming clips never expand, if the request bounds is outside of the current clip
913 // there is no need to copy/restore the area, so just devolve back to a regular save.
914 this->save();
915 } else {
916 bool doTheWork = this->onDoSaveBehind(bounds);
917 fSaveCount += 1;
918 this->internalSave();
919 if (doTheWork) {
920 this->internalSaveBehind(bounds);
921 }
922 }
923 return this->getSaveCount() - 1;
924}
925
reeda2217ef2016-07-20 06:04:34 -0700926void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500927 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500928 const SkMatrix& ctm) {
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400929 SkPaint p;
Michael Ludwig08b260c2019-05-17 11:21:53 -0400930 SkIRect snapBounds = SkIRect::MakeXYWH(dstOrigin.x() - src->getOrigin().x(),
931 dstOrigin.y() - src->getOrigin().y(),
932 dst->width(), dst->height());
933 int x = 0;
934 int y = 0;
935
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400936 if (filter) {
Michael Ludwig08b260c2019-05-17 11:21:53 -0400937 // Calculate expanded snap bounds
938 SkIRect newBounds = filter->filterBounds(
939 snapBounds, ctm, SkImageFilter::kReverse_MapDirection, &snapBounds);
940 // Must clamp to valid src since the filter or rotations may expand beyond what's readable
941 SkIRect srcR = SkIRect::MakeWH(src->width(), src->height());
942 if (!newBounds.intersect(srcR)) {
943 return;
944 }
945
946 x = newBounds.fLeft - snapBounds.fLeft;
947 y = newBounds.fTop - snapBounds.fTop;
948 snapBounds = newBounds;
949
950 SkMatrix localCTM;
951 sk_sp<SkImageFilter> modifiedFilter = SkApplyCTMToBackdropFilter(filter, ctm, &localCTM);
952 // Account for the origin offset in the CTM
953 localCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
954
955 // In this case we always wrap the filter (even when it's the original) with 'localCTM'
956 // since there's no device CTM stack that provides it to the image filter context.
957 // FIXME skbug.com/9074 - once perspective is properly supported, drop the
958 // localCTM.hasPerspective condition from assert.
959 SkASSERT(localCTM.isScaleTranslate() || filter->canHandleComplexCTM() ||
960 localCTM.hasPerspective());
961 p.setImageFilter(modifiedFilter->makeWithLocalMatrix(localCTM));
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400962 }
963
Michael Ludwig08b260c2019-05-17 11:21:53 -0400964 auto special = src->snapBackImage(snapBounds);
reeda2217ef2016-07-20 06:04:34 -0700965 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400966 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700967 }
robertphillips7354a4b2015-12-16 05:08:27 -0800968}
reed70ee31b2015-12-10 13:44:45 -0800969
Mike Reed25394292019-03-07 09:36:36 -0500970// This is shared by all backends, but contains raster-specific thoughts. Can we defer to the
971// device to perform this?
Mike Kleine083f7c2018-02-07 12:54:27 -0500972static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500973 // Need to force L32 for now if we have an image filter.
Mike Reed25394292019-03-07 09:36:36 -0500974 // If filters ever support other colortypes, e.g. F16, we can modify this check.
Mike Klein649fb732018-02-26 15:09:16 -0500975 if (paint && paint->getImageFilter()) {
Mike Reed25394292019-03-07 09:36:36 -0500976 // TODO: can we query the imagefilter, to see if it can handle floats (so we don't always
977 // use N32 when the layer itself was float)?
978 return SkImageInfo::MakeN32Premul(w, h, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800979 }
Mike Klein649fb732018-02-26 15:09:16 -0500980
981 SkColorType ct = prev.colorType();
982 if (prev.bytesPerPixel() <= 4) {
983 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
984 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
985 ct = kN32_SkColorType;
986 }
987 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800988}
989
reed4960eee2015-12-18 07:09:18 -0800990void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700991 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800992 const SkRect* bounds = rec.fBounds;
993 const SkPaint* paint = rec.fPaint;
994 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
995
Mike Reed5532c2a2019-02-23 12:00:32 -0500996 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
997 // regardless of any hint-rect from the caller. skbug.com/8783
998 if (rec.fBackdrop) {
999 bounds = nullptr;
1000 }
1001
reed8c30a812016-04-20 16:36:51 -07001002 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001003 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001004 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -04001005 MCRec* modifiedRec = nullptr;
Michael Ludwig08b260c2019-05-17 11:21:53 -04001006
reed8c30a812016-04-20 16:36:51 -07001007 /*
Michael Ludwig08b260c2019-05-17 11:21:53 -04001008 * Many ImageFilters (so far) do not (on their own) correctly handle matrices (CTM) that
1009 * contain rotation/skew/etc. We rely on applyCTM to create a new image filter DAG as needed to
1010 * accommodate this, but it requires update the CTM we use when drawing into the layer.
reed8c30a812016-04-20 16:36:51 -07001011 *
1012 * 1. Stash off the current CTM
Michael Ludwig08b260c2019-05-17 11:21:53 -04001013 * 2. Apply the CTM to imagefilter, which decomposes it into simple and complex transforms
1014 * if necessary.
1015 * 3. Wack the CTM to be the remaining scale matrix and use the modified imagefilter, which
1016 * is a MatrixImageFilter that contains the complex matrix.
reed8c30a812016-04-20 16:36:51 -07001017 * 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 -04001018 * 5. During restore, the MatrixImageFilter automatically applies complex stage to the output
reed8c30a812016-04-20 16:36:51 -07001019 * of the original imagefilter, and draw that (via drawSprite)
1020 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1021 *
1022 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1023 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1024 */
Michael Ludwig08b260c2019-05-17 11:21:53 -04001025 if (imageFilter) {
1026 SkMatrix modifiedCTM;
1027 sk_sp<SkImageFilter> modifiedFilter = SkApplyCTMToFilter(imageFilter, stashedMatrix,
1028 &modifiedCTM);
1029 if (!SkIsSameFilter(modifiedFilter.get(), imageFilter)) {
1030 // The original filter couldn't support the CTM entirely
1031 SkASSERT(modifiedCTM.isScaleTranslate() || imageFilter->canHandleComplexCTM());
1032 modifiedRec = fMCRec;
1033 this->internalSetMatrix(modifiedCTM);
1034 SkPaint* p = lazyP.set(*paint);
1035 p->setImageFilter(std::move(modifiedFilter));
1036 imageFilter = p->getImageFilter();
1037 paint = p;
1038 }
1039 // Else the filter didn't change, so modifiedCTM == stashedMatrix and there's nothing
1040 // left to do since the stack already has that as the CTM.
reed8c30a812016-04-20 16:36:51 -07001041 }
reed8c30a812016-04-20 16:36:51 -07001042
junov@chromium.orga907ac32012-02-24 21:54:07 +00001043 // do this before we create the layer. We don't call the public save() since
1044 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001045 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001046
junov@chromium.orga907ac32012-02-24 21:54:07 +00001047 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001048 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001049 if (modifiedRec) {
1050 // In this case there will be no layer in which to stash the matrix so we need to
1051 // revert the prior MCRec to its earlier state.
1052 modifiedRec->fMatrix = stashedMatrix;
1053 }
reed2ff1fce2014-12-11 07:07:37 -08001054 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055 }
1056
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001057 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1058 // the clipRectBounds() call above?
1059 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001060 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001061 }
1062
reed8dc0ccb2015-03-20 06:32:52 -07001063 SkPixelGeometry geo = fProps.pixelGeometry();
1064 if (paint) {
reed76033be2015-03-14 10:54:31 -07001065 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001066 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001067 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001068 }
1069 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001070
robertphillips5139e502016-07-19 05:10:40 -07001071 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001072 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001073 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001074 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001075 }
reedb2db8982014-11-13 12:41:02 -08001076
Mike Kleine083f7c2018-02-07 12:54:27 -05001077 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
Mike Reed1f3548c2019-07-12 12:53:11 -04001078 if (rec.fSaveLayerFlags & kF16ColorType) {
1079 info = info.makeColorType(kRGBA_F16_SkColorType);
1080 }
reed129ed1c2016-02-22 06:42:31 -08001081
Hal Canary704cd322016-11-07 14:13:52 -05001082 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001083 {
Florin Malita4571e492019-07-16 10:25:58 -04001084 SkASSERT(info.alphaType() != kOpaque_SkAlphaType);
reeddaa57bf2015-05-15 10:39:17 -07001085 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001086 const bool trackCoverage =
1087 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001088 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed910ca0f2018-04-25 13:04:05 -04001089 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001090 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001091 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1092 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001093 return;
reed61f501f2015-04-29 08:34:00 -07001094 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001095 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001096 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097
Mike Reedb43a3e02017-02-11 10:18:58 -05001098 // only have a "next" if this new layer doesn't affect the clip (rare)
1099 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100 fMCRec->fLayer = layer;
1101 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001102
Mike Reedc61abee2017-02-28 17:45:27 -05001103 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001104 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001105 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001106 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001107
Mike Reedc42a1cd2017-02-14 14:25:14 -05001108 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1109
1110 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1111 if (layer->fNext) {
1112 // need to punch a hole in the previous device, so we don't draw there, given that
1113 // the new top-layer will allow drawing to happen "below" it.
1114 SkRegion hole(ir);
1115 do {
1116 layer = layer->fNext;
1117 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1118 } while (layer->fNext);
1119 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001120}
1121
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001122int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001123 if (0xFF == alpha) {
1124 return this->saveLayer(bounds, nullptr);
1125 } else {
1126 SkPaint tmpPaint;
1127 tmpPaint.setAlpha(alpha);
1128 return this->saveLayer(bounds, &tmpPaint);
1129 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001130}
1131
Mike Reed148b7fd2018-12-18 17:38:18 -05001132void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1133 SkIRect devBounds;
1134 if (localBounds) {
1135 SkRect tmp;
1136 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1137 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1138 devBounds.setEmpty();
1139 }
1140 } else {
1141 devBounds = this->getDeviceClipBounds();
1142 }
1143 if (devBounds.isEmpty()) {
1144 return;
1145 }
1146
1147 SkBaseDevice* device = this->getTopDevice();
1148 if (nullptr == device) { // Do we still need this check???
1149 return;
1150 }
1151
1152 // need the bounds relative to the device itself
1153 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1154
1155 auto backImage = device->snapBackImage(devBounds);
1156 if (!backImage) {
1157 return;
1158 }
1159
1160 // we really need the save, so we can wack the fMCRec
1161 this->checkForDeferredSave();
1162
1163 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1164
1165 SkPaint paint;
1166 paint.setBlendMode(SkBlendMode::kClear);
Mike Reed9adc82c2019-04-23 10:28:13 -04001167 this->drawClippedToSaveBehind(paint);
Mike Reed148b7fd2018-12-18 17:38:18 -05001168}
1169
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170void SkCanvas::internalRestore() {
1171 SkASSERT(fMCStack.count() != 0);
1172
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001173 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001174 DeviceCM* layer = fMCRec->fLayer; // may be null
1175 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001176 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001177
Mike Reed148b7fd2018-12-18 17:38:18 -05001178 // move this out before we do the actual restore
1179 auto backImage = std::move(fMCRec->fBackImage);
1180
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181 // now do the normal restore()
1182 fMCRec->~MCRec(); // balanced in save()
1183 fMCStack.pop_back();
1184 fMCRec = (MCRec*)fMCStack.back();
1185
Mike Reedc42a1cd2017-02-14 14:25:14 -05001186 if (fMCRec) {
1187 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1188 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001189
Mike Reed148b7fd2018-12-18 17:38:18 -05001190 if (backImage) {
1191 SkPaint paint;
1192 paint.setBlendMode(SkBlendMode::kDstOver);
1193 const int x = backImage->fLoc.x();
1194 const int y = backImage->fLoc.y();
1195 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1196 nullptr, SkMatrix::I());
1197 }
1198
reed@android.com8a1c16f2008-12-17 15:59:43 +00001199 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1200 since if we're being recorded, we don't want to record this (the
1201 recorder will have already recorded the restore).
1202 */
bsalomon49f085d2014-09-05 13:34:00 -07001203 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001204 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001205 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001206 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001207 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001208 layer->fPaint.get(),
1209 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001210 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001211 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001212 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001213 delete layer;
reedb679ca82015-04-07 04:40:48 -07001214 } else {
1215 // we're at the root
reeda499f902015-05-01 09:34:31 -07001216 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001217 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001218 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001219 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001220 }
msarettfbfa2582016-08-12 08:29:08 -07001221
1222 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001223 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001224 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1225 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226}
1227
reede8f30622016-03-23 18:59:25 -07001228sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001229 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001230 props = &fProps;
1231 }
1232 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001233}
1234
reede8f30622016-03-23 18:59:25 -07001235sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001236 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001237 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001238}
1239
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001240SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001241 return this->onImageInfo();
1242}
1243
1244SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001245 SkBaseDevice* dev = this->getDevice();
1246 if (dev) {
1247 return dev->imageInfo();
1248 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001249 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001250 }
1251}
1252
brianosman898235c2016-04-06 07:38:23 -07001253bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001254 return this->onGetProps(props);
1255}
1256
1257bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001258 SkBaseDevice* dev = this->getDevice();
1259 if (dev) {
1260 if (props) {
1261 *props = fProps;
1262 }
1263 return true;
1264 } else {
1265 return false;
1266 }
1267}
1268
reed6ceeebd2016-03-09 14:26:26 -08001269bool SkCanvas::peekPixels(SkPixmap* pmap) {
1270 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001271}
1272
reed884e97c2015-05-26 11:31:54 -07001273bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001274 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001275 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001276}
1277
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001278void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001279 SkPixmap pmap;
1280 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001281 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001282 }
1283 if (info) {
1284 *info = pmap.info();
1285 }
1286 if (rowBytes) {
1287 *rowBytes = pmap.rowBytes();
1288 }
1289 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001290 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001291 }
reed884e97c2015-05-26 11:31:54 -07001292 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001293}
1294
reed884e97c2015-05-26 11:31:54 -07001295bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001296 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001297 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001298}
1299
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301
Mike Reed8bcd1282019-03-13 16:51:54 -04001302// In our current design/features, we should never have a layer (src) in a different colorspace
1303// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1304// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1305// colorspace.
1306static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1307 SkASSERT(src == dst);
1308}
1309
Florin Malita53f77bd2017-04-28 13:48:37 -04001310void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1311 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001312 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001313 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314 paint = &tmp;
1315 }
reed@google.com4b226022011-01-11 18:32:13 +00001316
Ben Wagner2c312c42018-06-27 14:46:46 -04001317 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001318
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001320 SkBaseDevice* dstDev = iter.fDevice;
Mike Reed8bcd1282019-03-13 16:51:54 -04001321 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1322 srcDev->imageInfo().colorSpace());
reed@google.com76dd2772012-01-05 21:15:07 +00001323 paint = &looper.paint();
1324 SkImageFilter* filter = paint->getImageFilter();
1325 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001326 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001327 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1328 if (specialImage) {
Mike Reed8bcd1282019-03-13 16:51:54 -04001329 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1330 specialImage->getColorSpace());
Florin Malita53f77bd2017-04-28 13:48:37 -04001331 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1332 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001333 }
reed@google.com76dd2772012-01-05 21:15:07 +00001334 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001335 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001336 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337 }
reeda2217ef2016-07-20 06:04:34 -07001338
reed@google.com4e2b3d32011-04-07 14:18:59 +00001339 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340}
1341
reed32704672015-12-16 08:27:10 -08001342/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001343
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001344void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001345 if (dx || dy) {
1346 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001347 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001348
reedfe69b502016-09-12 06:31:48 -07001349 // Translate shouldn't affect the is-scale-translateness of the matrix.
1350 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001351
Mike Reedc42a1cd2017-02-14 14:25:14 -05001352 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001353
reedfe69b502016-09-12 06:31:48 -07001354 this->didTranslate(dx,dy);
1355 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356}
1357
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001358void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001359 SkMatrix m;
1360 m.setScale(sx, sy);
1361 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001362}
1363
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001364void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001365 SkMatrix m;
1366 m.setRotate(degrees);
1367 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001368}
1369
bungeman7438bfc2016-07-12 15:01:19 -07001370void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1371 SkMatrix m;
1372 m.setRotate(degrees, px, py);
1373 this->concat(m);
1374}
1375
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001376void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001377 SkMatrix m;
1378 m.setSkew(sx, sy);
1379 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001380}
1381
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001382void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001383 if (matrix.isIdentity()) {
1384 return;
1385 }
1386
reed2ff1fce2014-12-11 07:07:37 -08001387 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001388 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001389 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001390
Mike Reed7627fa52017-02-08 10:07:53 -05001391 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001392
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001393 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001394}
1395
reed8c30a812016-04-20 16:36:51 -07001396void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001397 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001398 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001399
Mike Reedc42a1cd2017-02-14 14:25:14 -05001400 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001401}
1402
1403void SkCanvas::setMatrix(const SkMatrix& matrix) {
1404 this->checkForDeferredSave();
1405 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001406 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407}
1408
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001410 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001411}
1412
1413//////////////////////////////////////////////////////////////////////////////
1414
Mike Reedc1f77742016-12-09 09:00:50 -05001415void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001416 if (!rect.isFinite()) {
1417 return;
1418 }
reed2ff1fce2014-12-11 07:07:37 -08001419 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001420 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1421 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001422}
1423
Mike Reedc1f77742016-12-09 09:00:50 -05001424void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001425 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001426
Mike Reed7627fa52017-02-08 10:07:53 -05001427 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001428
reedc64eff52015-11-21 12:39:45 -08001429 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001430 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1431 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001432 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433}
1434
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001435void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1436 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001437 if (fClipRestrictionRect.isEmpty()) {
1438 // we notify the device, but we *dont* resolve deferred saves (since we're just
1439 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001440 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001441 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001442 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001443 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001444 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001445 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001446 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1447 }
1448}
1449
Mike Reedc1f77742016-12-09 09:00:50 -05001450void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001451 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001452 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001453 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001454 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1455 } else {
1456 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001457 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001458}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001459
Mike Reedc1f77742016-12-09 09:00:50 -05001460void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001461 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001462
Brian Salomona3b45d42016-10-03 11:36:16 -04001463 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001464
Mike Reed7627fa52017-02-08 10:07:53 -05001465 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001466
Mike Reed20800c82017-11-15 16:09:04 -05001467 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1468 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001469 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001470}
1471
Mike Reedc1f77742016-12-09 09:00:50 -05001472void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001473 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001474 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001475
1476 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1477 SkRect r;
1478 if (path.isRect(&r)) {
1479 this->onClipRect(r, op, edgeStyle);
1480 return;
1481 }
1482 SkRRect rrect;
1483 if (path.isOval(&r)) {
1484 rrect.setOval(r);
1485 this->onClipRRect(rrect, op, edgeStyle);
1486 return;
1487 }
1488 if (path.isRRect(&rrect)) {
1489 this->onClipRRect(rrect, op, edgeStyle);
1490 return;
1491 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001492 }
robertphillips39f05382015-11-24 09:30:12 -08001493
1494 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001495}
1496
Mike Reedc1f77742016-12-09 09:00:50 -05001497void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001498 AutoValidateClip avc(this);
1499
Brian Salomona3b45d42016-10-03 11:36:16 -04001500 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001501
Mike Reed7627fa52017-02-08 10:07:53 -05001502 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503
Brian Salomona3b45d42016-10-03 11:36:16 -04001504 const SkPath* rasterClipPath = &path;
1505 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001506 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1507 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001508 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001509}
1510
Mike Reedc1f77742016-12-09 09:00:50 -05001511void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001512 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001513 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001514}
1515
Mike Reedc1f77742016-12-09 09:00:50 -05001516void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001517 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001518
reed@google.com5c3d1472011-02-22 19:12:23 +00001519 AutoValidateClip avc(this);
1520
Mike Reed20800c82017-11-15 16:09:04 -05001521 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001522 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001523}
1524
reed@google.com819c9212011-02-23 18:56:55 +00001525#ifdef SK_DEBUG
1526void SkCanvas::validateClip() const {
1527 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001528 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001529 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001530 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001531 return;
1532 }
reed@google.com819c9212011-02-23 18:56:55 +00001533}
1534#endif
1535
Mike Reeda1361362017-03-07 09:37:29 -05001536bool SkCanvas::androidFramework_isClipAA() const {
1537 bool containsAA = false;
1538
1539 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1540
1541 return containsAA;
1542}
1543
1544class RgnAccumulator {
1545 SkRegion* fRgn;
1546public:
1547 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1548 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1549 SkIPoint origin = device->getOrigin();
1550 if (origin.x() | origin.y()) {
1551 rgn->translate(origin.x(), origin.y());
1552 }
1553 fRgn->op(*rgn, SkRegion::kUnion_Op);
1554 }
1555};
1556
1557void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1558 RgnAccumulator accum(rgn);
1559 SkRegion tmp;
1560
1561 rgn->setEmpty();
1562 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001563}
1564
reed@google.com5c3d1472011-02-22 19:12:23 +00001565///////////////////////////////////////////////////////////////////////////////
1566
reed@google.com754de5f2014-02-24 19:38:20 +00001567bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001568 return fMCRec->fRasterClip.isEmpty();
1569
1570 // TODO: should we only use the conservative answer in a recording canvas?
1571#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001572 SkBaseDevice* dev = this->getTopDevice();
1573 // if no device we return true
1574 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001575#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001576}
1577
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001578bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001579 SkBaseDevice* dev = this->getTopDevice();
1580 // if no device we return false
1581 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001582}
1583
msarettfbfa2582016-08-12 08:29:08 -07001584static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1585#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1586 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1587 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1588 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1589 return 0xF != _mm_movemask_ps(mask);
1590#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1591 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1592 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1593 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1594 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1595#else
1596 SkRect devRectAsRect;
1597 SkRect devClipAsRect;
1598 devRect.store(&devRectAsRect.fLeft);
1599 devClip.store(&devClipAsRect.fLeft);
1600 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1601#endif
1602}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001603
msarettfbfa2582016-08-12 08:29:08 -07001604// It's important for this function to not be inlined. Otherwise the compiler will share code
1605// between the fast path and the slow path, resulting in two slow paths.
1606static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1607 const SkMatrix& matrix) {
1608 SkRect deviceRect;
1609 matrix.mapRect(&deviceRect, src);
1610 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1611}
1612
1613bool SkCanvas::quickReject(const SkRect& src) const {
1614#ifdef SK_DEBUG
1615 // Verify that fDeviceClipBounds are set properly.
1616 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001617 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001618 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001619 } else {
msarettfbfa2582016-08-12 08:29:08 -07001620 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001621 }
msarettfbfa2582016-08-12 08:29:08 -07001622
msarett9637ea92016-08-18 14:03:30 -07001623 // Verify that fIsScaleTranslate is set properly.
1624 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001625#endif
1626
msarett9637ea92016-08-18 14:03:30 -07001627 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001628 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1629 }
1630
1631 // We inline the implementation of mapScaleTranslate() for the fast path.
1632 float sx = fMCRec->fMatrix.getScaleX();
1633 float sy = fMCRec->fMatrix.getScaleY();
1634 float tx = fMCRec->fMatrix.getTranslateX();
1635 float ty = fMCRec->fMatrix.getTranslateY();
1636 Sk4f scale(sx, sy, sx, sy);
1637 Sk4f trans(tx, ty, tx, ty);
1638
1639 // Apply matrix.
1640 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1641
1642 // Make sure left < right, top < bottom.
1643 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1644 Sk4f min = Sk4f::Min(ltrb, rblt);
1645 Sk4f max = Sk4f::Max(ltrb, rblt);
1646 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1647 // ARM this sequence generates the fastest (a single instruction).
1648 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1649
1650 // Check if the device rect is NaN or outside the clip.
1651 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652}
1653
reed@google.com3b3e8952012-08-16 20:53:31 +00001654bool SkCanvas::quickReject(const SkPath& path) const {
1655 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001656}
1657
Mike Klein83c8dd92017-11-28 17:08:45 -05001658SkRect SkCanvas::getLocalClipBounds() const {
1659 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001660 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001661 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662 }
1663
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001664 SkMatrix inverse;
1665 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001666 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001667 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001668 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001669
Mike Reed42e8c532017-01-23 14:09:13 -05001670 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001671 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001672 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001673
Mike Reedb57b9312018-04-23 12:12:54 -04001674 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001675 inverse.mapRect(&bounds, r);
1676 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001677}
1678
Mike Klein83c8dd92017-11-28 17:08:45 -05001679SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001680 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001681}
1682
reed@android.com8a1c16f2008-12-17 15:59:43 +00001683const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001684 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001685}
1686
Brian Osman11052242016-10-27 14:47:55 -04001687GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001688 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001689 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001690}
1691
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001692GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001693 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001694 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001695}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001696
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001697void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1698 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001699 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001700 if (outer.isEmpty()) {
1701 return;
1702 }
1703 if (inner.isEmpty()) {
1704 this->drawRRect(outer, paint);
1705 return;
1706 }
1707
1708 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001709 // be able to return ...
1710 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001711 //
1712 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001713 if (!outer.getBounds().contains(inner.getBounds())) {
1714 return;
1715 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001716
1717 this->onDrawDRRect(outer, inner, paint);
1718}
1719
reed41af9662015-01-05 07:49:08 -08001720void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001721 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001722 this->onDrawPaint(paint);
1723}
1724
1725void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001726 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001727 // To avoid redundant logic in our culling code and various backends, we always sort rects
1728 // before passing them along.
1729 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001730}
1731
Mike Reedd5674082019-04-19 15:00:47 -04001732void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1733 TRACE_EVENT0("skia", TRACE_FUNC);
1734 this->onDrawBehind(paint);
1735}
1736
msarettdca352e2016-08-26 06:37:45 -07001737void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001738 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001739 if (region.isEmpty()) {
1740 return;
1741 }
1742
1743 if (region.isRect()) {
1744 return this->drawIRect(region.getBounds(), paint);
1745 }
1746
1747 this->onDrawRegion(region, paint);
1748}
1749
reed41af9662015-01-05 07:49:08 -08001750void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001751 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001752 // To avoid redundant logic in our culling code and various backends, we always sort rects
1753 // before passing them along.
1754 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001755}
1756
1757void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001758 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001759 this->onDrawRRect(rrect, paint);
1760}
1761
1762void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001763 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001764 this->onDrawPoints(mode, count, pts, paint);
1765}
1766
Mike Reede88a1cb2017-03-17 09:50:46 -04001767void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1768 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001769 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001770 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001771 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1772 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001773 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001774}
1775
1776void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001777 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001778 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001779 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1780}
1781
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001782void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1783 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001784 TRACE_EVENT0("skia", TRACE_FUNC);
1785 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001786 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001787 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1788}
1789
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001790void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1791 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001792 TRACE_EVENT0("skia", TRACE_FUNC);
1793 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001794 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001795 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001796}
1797
1798void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001799 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001800 this->onDrawPath(path, paint);
1801}
1802
reeda85d4d02015-05-06 12:56:48 -07001803void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001804 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001805 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001806 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001807}
1808
Mike Reedc4e31092018-01-30 11:15:27 -05001809// Returns true if the rect can be "filled" : non-empty and finite
1810static bool fillable(const SkRect& r) {
1811 SkScalar w = r.width();
1812 SkScalar h = r.height();
1813 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1814}
1815
reede47829b2015-08-06 10:02:53 -07001816void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1817 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001818 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001819 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001820 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001821 return;
1822 }
1823 this->onDrawImageRect(image, &src, dst, paint, constraint);
1824}
reed41af9662015-01-05 07:49:08 -08001825
reed84984ef2015-07-17 07:09:43 -07001826void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1827 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001828 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001829 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001830}
1831
Brian Salomonf08002c2018-10-26 16:15:46 -04001832void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001833 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001834 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001835 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001836}
reede47829b2015-08-06 10:02:53 -07001837
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001838namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001839class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001840public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001841 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1842 if (!origPaint) {
1843 return;
1844 }
1845 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1846 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1847 }
1848 if (origPaint->getMaskFilter()) {
1849 fPaint.writable()->setMaskFilter(nullptr);
1850 }
1851 if (origPaint->isAntiAlias()) {
1852 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001853 }
1854 }
1855
1856 const SkPaint* get() const {
1857 return fPaint;
1858 }
1859
1860private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001861 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001862};
1863} // namespace
1864
reed4c21dc52015-06-25 12:32:03 -07001865void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1866 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001867 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001868 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001869 if (dst.isEmpty()) {
1870 return;
1871 }
msarett552bca92016-08-03 06:53:26 -07001872 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001873 LatticePaint latticePaint(paint);
1874 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001875 } else {
reede47829b2015-08-06 10:02:53 -07001876 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001877 }
reed4c21dc52015-06-25 12:32:03 -07001878}
1879
msarett16882062016-08-16 09:31:08 -07001880void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1881 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001882 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001883 RETURN_ON_NULL(image);
1884 if (dst.isEmpty()) {
1885 return;
1886 }
msarett71df2d72016-09-30 12:41:42 -07001887
1888 SkIRect bounds;
1889 Lattice latticePlusBounds = lattice;
1890 if (!latticePlusBounds.fBounds) {
1891 bounds = SkIRect::MakeWH(image->width(), image->height());
1892 latticePlusBounds.fBounds = &bounds;
1893 }
1894
1895 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001896 LatticePaint latticePaint(paint);
1897 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001898 } else {
1899 this->drawImageRect(image, dst, paint);
1900 }
1901}
1902
reed41af9662015-01-05 07:49:08 -08001903void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001904 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001905 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001906 return;
1907 }
reed41af9662015-01-05 07:49:08 -08001908 this->onDrawBitmap(bitmap, dx, dy, paint);
1909}
1910
reede47829b2015-08-06 10:02:53 -07001911void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001912 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001913 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001914 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001915 return;
1916 }
reede47829b2015-08-06 10:02:53 -07001917 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001918}
1919
reed84984ef2015-07-17 07:09:43 -07001920void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1921 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001922 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001923}
1924
reede47829b2015-08-06 10:02:53 -07001925void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1926 SrcRectConstraint constraint) {
1927 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1928 constraint);
1929}
reede47829b2015-08-06 10:02:53 -07001930
reed41af9662015-01-05 07:49:08 -08001931void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1932 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001933 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001934 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001935 return;
1936 }
msarett552bca92016-08-03 06:53:26 -07001937 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001938 LatticePaint latticePaint(paint);
1939 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001940 } else {
reeda5517e22015-07-14 10:54:12 -07001941 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001942 }
reed41af9662015-01-05 07:49:08 -08001943}
1944
msarettc573a402016-08-02 08:05:56 -07001945void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1946 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001947 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001948 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001949 return;
1950 }
msarett71df2d72016-09-30 12:41:42 -07001951
1952 SkIRect bounds;
1953 Lattice latticePlusBounds = lattice;
1954 if (!latticePlusBounds.fBounds) {
1955 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1956 latticePlusBounds.fBounds = &bounds;
1957 }
1958
1959 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001960 LatticePaint latticePaint(paint);
1961 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001962 } else {
msarett16882062016-08-16 09:31:08 -07001963 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001964 }
msarettc573a402016-08-02 08:05:56 -07001965}
1966
reed71c3c762015-06-24 10:29:17 -07001967void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001968 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001969 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001970 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001971 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001972 if (count <= 0) {
1973 return;
1974 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001975 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001976 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001977 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001978}
1979
reedf70b5312016-03-04 16:36:20 -08001980void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001981 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001982 if (key) {
1983 this->onDrawAnnotation(rect, key, value);
1984 }
1985}
1986
reede47829b2015-08-06 10:02:53 -07001987void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1988 const SkPaint* paint, SrcRectConstraint constraint) {
1989 if (src) {
1990 this->drawImageRect(image, *src, dst, paint, constraint);
1991 } else {
1992 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1993 dst, paint, constraint);
1994 }
1995}
1996void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1997 const SkPaint* paint, SrcRectConstraint constraint) {
1998 if (src) {
1999 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2000 } else {
2001 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2002 dst, paint, constraint);
2003 }
2004}
2005
Mike Reed4204da22017-05-17 08:53:36 -04002006void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002007 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04002008 this->onDrawShadowRec(path, rec);
2009}
2010
2011void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
2012 SkPaint paint;
2013 const SkRect& pathBounds = path.getBounds();
2014
Ben Wagner2c312c42018-06-27 14:46:46 -04002015 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04002016 while (iter.next()) {
2017 iter.fDevice->drawShadow(path, rec);
2018 }
2019 LOOPER_END
2020}
2021
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002022void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2023 QuadAAFlags aaFlags, SkColor color, SkBlendMode mode) {
2024 TRACE_EVENT0("skia", TRACE_FUNC);
2025 // Make sure the rect is sorted before passing it along
2026 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2027}
2028
2029void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2030 const SkPoint dstClips[],
2031 const SkMatrix preViewMatrices[],
2032 const SkPaint* paint,
2033 SrcRectConstraint constraint) {
2034 TRACE_EVENT0("skia", TRACE_FUNC);
2035 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2036}
2037
reed@android.com8a1c16f2008-12-17 15:59:43 +00002038//////////////////////////////////////////////////////////////////////////////
2039// These are the virtual drawing methods
2040//////////////////////////////////////////////////////////////////////////////
2041
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002042void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002043 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002044 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2045 }
2046}
2047
reed41af9662015-01-05 07:49:08 -08002048void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002049 this->internalDrawPaint(paint);
2050}
2051
2052void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002053 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002054
2055 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002056 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002057 }
2058
reed@google.com4e2b3d32011-04-07 14:18:59 +00002059 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002060}
2061
reed41af9662015-01-05 07:49:08 -08002062void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2063 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002064 if ((long)count <= 0) {
2065 return;
2066 }
2067
Mike Reed822128b2017-02-28 16:41:03 -05002068 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002069 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002070 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002071 // special-case 2 points (common for drawing a single line)
2072 if (2 == count) {
2073 r.set(pts[0], pts[1]);
2074 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002075 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002076 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002077 if (!r.isFinite()) {
2078 return;
2079 }
Mike Reed822128b2017-02-28 16:41:03 -05002080 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002081 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2082 return;
2083 }
2084 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002085 }
reed@google.coma584aed2012-05-16 14:06:02 +00002086
halcanary96fcdcc2015-08-27 07:41:13 -07002087 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002088
Ben Wagner2c312c42018-06-27 14:46:46 -04002089 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002090
reed@android.com8a1c16f2008-12-17 15:59:43 +00002091 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002092 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093 }
reed@google.com4b226022011-01-11 18:32:13 +00002094
reed@google.com4e2b3d32011-04-07 14:18:59 +00002095 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002096}
2097
reed4a167172016-08-18 17:15:25 -07002098static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
Mike Reed9dc0b9e2019-07-29 17:52:48 -04002099 return paint.getImageFilter() != nullptr;
reed4a167172016-08-18 17:15:25 -07002100}
2101
reed41af9662015-01-05 07:49:08 -08002102void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002103 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002104 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002105 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002106 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002107 return;
2108 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002109 }
reed@google.com4b226022011-01-11 18:32:13 +00002110
reed4a167172016-08-18 17:15:25 -07002111 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002112 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002113
reed4a167172016-08-18 17:15:25 -07002114 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002115 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002116 }
2117
2118 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002119 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002120 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002121 SkDrawIter iter(this);
2122 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002123 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002124 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002125 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002126}
2127
msarett44df6512016-08-25 13:54:30 -07002128void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002129 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002130 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002131 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002132 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2133 return;
2134 }
msarett44df6512016-08-25 13:54:30 -07002135 }
2136
Ben Wagner2c312c42018-06-27 14:46:46 -04002137 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002138
2139 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002140 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002141 }
2142
2143 LOOPER_END
2144}
2145
Mike Reedd5674082019-04-19 15:00:47 -04002146void SkCanvas::onDrawBehind(const SkPaint& paint) {
2147 SkIRect bounds;
2148 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2149 for (;;) {
2150 const MCRec* rec = (const MCRec*)iter.prev();
2151 if (!rec) {
2152 return; // no backimages, so nothing to draw
2153 }
2154 if (rec->fBackImage) {
2155 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2156 rec->fBackImage->fImage->width(),
2157 rec->fBackImage->fImage->height());
2158 break;
2159 }
2160 }
2161
2162 LOOPER_BEGIN(paint, nullptr)
2163
2164 while (iter.next()) {
2165 SkBaseDevice* dev = iter.fDevice;
2166
Mike Reedd5674082019-04-19 15:00:47 -04002167 dev->save();
2168 // We use clipRegion because it is already defined to operate in dev-space
2169 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2170 // but we don't want that, so we undo that before calling in.
2171 SkRegion rgn(bounds.makeOffset(dev->fOrigin.fX, dev->fOrigin.fY));
2172 dev->clipRegion(rgn, SkClipOp::kIntersect);
2173 dev->drawPaint(looper.paint());
Mike Reed9adc82c2019-04-23 10:28:13 -04002174 dev->restore(fMCRec->fMatrix);
Mike Reedd5674082019-04-19 15:00:47 -04002175 }
2176
2177 LOOPER_END
2178}
2179
reed41af9662015-01-05 07:49:08 -08002180void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002181 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002182 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002183 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002184 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002185 return;
2186 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002187 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002188
Ben Wagner2c312c42018-06-27 14:46:46 -04002189 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002190
2191 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002192 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002193 }
2194
2195 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002196}
2197
bsalomonac3aa242016-08-19 11:25:19 -07002198void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2199 SkScalar sweepAngle, bool useCenter,
2200 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002201 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002202 if (paint.canComputeFastBounds()) {
2203 SkRect storage;
2204 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002205 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002206 return;
2207 }
bsalomonac3aa242016-08-19 11:25:19 -07002208 }
2209
Ben Wagner2c312c42018-06-27 14:46:46 -04002210 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002211
2212 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002213 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002214 }
2215
2216 LOOPER_END
2217}
2218
reed41af9662015-01-05 07:49:08 -08002219void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002220 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002221 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002222 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2223 return;
2224 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002225 }
2226
2227 if (rrect.isRect()) {
2228 // call the non-virtual version
2229 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002230 return;
2231 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002232 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002233 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2234 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002235 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002236
Ben Wagner2c312c42018-06-27 14:46:46 -04002237 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002238
2239 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002240 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002241 }
2242
2243 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002244}
2245
Mike Reed822128b2017-02-28 16:41:03 -05002246void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002247 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002248 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002249 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2250 return;
2251 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002252 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002253
Ben Wagner2c312c42018-06-27 14:46:46 -04002254 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002255
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002256 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002257 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002258 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002259
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002260 LOOPER_END
2261}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002262
reed41af9662015-01-05 07:49:08 -08002263void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002264 if (!path.isFinite()) {
2265 return;
2266 }
2267
Mike Reed822128b2017-02-28 16:41:03 -05002268 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002269 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002270 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002271 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2272 return;
2273 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002274 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002275
Mike Reed822128b2017-02-28 16:41:03 -05002276 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002277 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002278 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002279 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002280 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002281 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002282
Ben Wagner2c312c42018-06-27 14:46:46 -04002283 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002284
2285 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002286 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002287 }
2288
reed@google.com4e2b3d32011-04-07 14:18:59 +00002289 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290}
2291
reed262a71b2015-12-05 13:07:27 -08002292bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002293 if (!paint.getImageFilter()) {
2294 return false;
2295 }
2296
2297 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002298 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002299 return false;
2300 }
2301
2302 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2303 // Once we can filter and the filter will return a result larger than itself, we should be
2304 // able to remove this constraint.
2305 // skbug.com/4526
2306 //
2307 SkPoint pt;
2308 ctm.mapXY(x, y, &pt);
2309 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2310 return ir.contains(fMCRec->fRasterClip.getBounds());
2311}
2312
Mike Reedf441cfc2018-04-11 14:50:16 -04002313// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2314// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2315// null.
2316static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2317 if (paintParam) {
2318 *real = *paintParam;
2319 real->setStyle(SkPaint::kFill_Style);
2320 real->setPathEffect(nullptr);
2321 paintParam = real;
2322 }
2323 return paintParam;
2324}
2325
reeda85d4d02015-05-06 12:56:48 -07002326void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002327 SkPaint realPaint;
2328 paint = init_image_paint(&realPaint, paint);
2329
reeda85d4d02015-05-06 12:56:48 -07002330 SkRect bounds = SkRect::MakeXYWH(x, y,
2331 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002332 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002333 SkRect tmp = bounds;
2334 if (paint) {
2335 paint->computeFastBounds(tmp, &tmp);
2336 }
2337 if (this->quickReject(tmp)) {
2338 return;
2339 }
reeda85d4d02015-05-06 12:56:48 -07002340 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002341 // At this point we need a real paint object. If the caller passed null, then we should
2342 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2343 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2344 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002345
reeda2217ef2016-07-20 06:04:34 -07002346 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002347 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2348 *paint);
2349 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002350 special = this->getDevice()->makeSpecial(image);
2351 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002352 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002353 }
2354 }
2355
reed262a71b2015-12-05 13:07:27 -08002356 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2357
reeda85d4d02015-05-06 12:56:48 -07002358 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002359 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002360 if (special) {
2361 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002362 iter.fDevice->ctm().mapXY(x, y, &pt);
2363 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002364 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002365 SkScalarRoundToInt(pt.fY), pnt,
2366 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002367 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002368 iter.fDevice->drawImageRect(
2369 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2370 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002371 }
reeda85d4d02015-05-06 12:56:48 -07002372 }
halcanary9d524f22016-03-29 09:03:52 -07002373
reeda85d4d02015-05-06 12:56:48 -07002374 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002375}
2376
reed41af9662015-01-05 07:49:08 -08002377void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002378 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002379 SkPaint realPaint;
2380 paint = init_image_paint(&realPaint, paint);
2381
halcanary96fcdcc2015-08-27 07:41:13 -07002382 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002383 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002384 if (paint) {
2385 paint->computeFastBounds(dst, &storage);
2386 }
2387 if (this->quickReject(storage)) {
2388 return;
2389 }
reeda85d4d02015-05-06 12:56:48 -07002390 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002391 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002392
Ben Wagner2c312c42018-06-27 14:46:46 -04002393 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002394
reeda85d4d02015-05-06 12:56:48 -07002395 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002396 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002397 }
halcanary9d524f22016-03-29 09:03:52 -07002398
reeda85d4d02015-05-06 12:56:48 -07002399 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002400}
2401
reed41af9662015-01-05 07:49:08 -08002402void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002403 SkDEBUGCODE(bitmap.validate();)
2404
reed33366972015-10-08 09:22:02 -07002405 if (bitmap.drawsNothing()) {
2406 return;
2407 }
2408
Mike Reedf441cfc2018-04-11 14:50:16 -04002409 SkPaint realPaint;
2410 init_image_paint(&realPaint, paint);
2411 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002412
Mike Reed822128b2017-02-28 16:41:03 -05002413 SkRect bounds;
2414 bitmap.getBounds(&bounds);
2415 bounds.offset(x, y);
2416 bool canFastBounds = paint->canComputeFastBounds();
2417 if (canFastBounds) {
2418 SkRect storage;
2419 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002420 return;
2421 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002422 }
reed@google.com4b226022011-01-11 18:32:13 +00002423
reeda2217ef2016-07-20 06:04:34 -07002424 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002425 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2426 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002427 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002428 special = this->getDevice()->makeSpecial(bitmap);
2429 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002430 drawAsSprite = false;
2431 }
2432 }
2433
Mike Reed822128b2017-02-28 16:41:03 -05002434 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002435
2436 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002437 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002438 if (special) {
reed262a71b2015-12-05 13:07:27 -08002439 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002440 iter.fDevice->ctm().mapXY(x, y, &pt);
2441 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002442 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002443 SkScalarRoundToInt(pt.fY), pnt,
2444 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002445 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002446 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2447 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2448 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002449 }
reed33366972015-10-08 09:22:02 -07002450 }
msarettfbfa2582016-08-12 08:29:08 -07002451
reed33366972015-10-08 09:22:02 -07002452 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002453}
2454
reed@google.com9987ec32011-09-07 11:57:52 +00002455// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002456void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002457 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002458 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002459 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002460 return;
2461 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002462
halcanary96fcdcc2015-08-27 07:41:13 -07002463 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002464 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002465 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2466 return;
2467 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002468 }
reed@google.com3d608122011-11-21 15:16:16 +00002469
reed@google.com33535f32012-09-25 15:37:50 +00002470 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002471 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002472 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002474
Ben Wagner2c312c42018-06-27 14:46:46 -04002475 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002476
reed@google.com33535f32012-09-25 15:37:50 +00002477 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002478 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002479 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002480
reed@google.com33535f32012-09-25 15:37:50 +00002481 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482}
2483
reed41af9662015-01-05 07:49:08 -08002484void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002485 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002486 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002487 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002488}
2489
reed4c21dc52015-06-25 12:32:03 -07002490void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2491 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002492 SkPaint realPaint;
2493 paint = init_image_paint(&realPaint, paint);
2494
halcanary96fcdcc2015-08-27 07:41:13 -07002495 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002496 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002497 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2498 return;
2499 }
reed@google.com3d608122011-11-21 15:16:16 +00002500 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002501 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002502
Ben Wagner2c312c42018-06-27 14:46:46 -04002503 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002504
reed4c21dc52015-06-25 12:32:03 -07002505 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002506 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002507 }
halcanary9d524f22016-03-29 09:03:52 -07002508
reed4c21dc52015-06-25 12:32:03 -07002509 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002510}
2511
reed41af9662015-01-05 07:49:08 -08002512void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2513 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002514 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002515 SkPaint realPaint;
2516 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002517
halcanary96fcdcc2015-08-27 07:41:13 -07002518 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002519 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002520 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2521 return;
2522 }
reed4c21dc52015-06-25 12:32:03 -07002523 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002524 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002525
Ben Wagner2c312c42018-06-27 14:46:46 -04002526 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002527
reed4c21dc52015-06-25 12:32:03 -07002528 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002529 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002530 }
halcanary9d524f22016-03-29 09:03:52 -07002531
reed4c21dc52015-06-25 12:32:03 -07002532 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002533}
2534
msarett16882062016-08-16 09:31:08 -07002535void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2536 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002537 SkPaint realPaint;
2538 paint = init_image_paint(&realPaint, paint);
2539
msarett16882062016-08-16 09:31:08 -07002540 if (nullptr == paint || paint->canComputeFastBounds()) {
2541 SkRect storage;
2542 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2543 return;
2544 }
2545 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002546 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002547
Ben Wagner2c312c42018-06-27 14:46:46 -04002548 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002549
2550 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002551 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002552 }
2553
2554 LOOPER_END
2555}
2556
2557void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2558 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002559 SkPaint realPaint;
2560 paint = init_image_paint(&realPaint, paint);
2561
msarett16882062016-08-16 09:31:08 -07002562 if (nullptr == paint || paint->canComputeFastBounds()) {
2563 SkRect storage;
2564 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2565 return;
2566 }
2567 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002568 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002569
Ben Wagner2c312c42018-06-27 14:46:46 -04002570 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002571
2572 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002573 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002574 }
2575
2576 LOOPER_END
2577}
2578
fmalita00d5c2c2014-08-21 08:53:26 -07002579void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2580 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002581 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002582 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002583 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002584 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002585 SkRect tmp;
2586 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2587 return;
2588 }
2589 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002590 }
2591
fmalita024f9962015-03-03 19:08:17 -08002592 // We cannot filter in the looper as we normally do, because the paint is
2593 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002594 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002595
fmalitaaa1b9122014-08-28 14:32:24 -07002596 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002597 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002598 }
2599
fmalitaaa1b9122014-08-28 14:32:24 -07002600 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002601}
2602
Mike Reed358fcad2018-11-23 15:27:51 -05002603// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002604void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002605 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2606 TRACE_EVENT0("skia", TRACE_FUNC);
2607 if (byteLength) {
2608 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002609 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002610 }
2611}
Mike Reed4f81bb72019-01-23 09:23:00 -05002612
fmalita00d5c2c2014-08-21 08:53:26 -07002613void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2614 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002615 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002616 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002617 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002618 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002619}
reed@google.come0d9ce82014-04-23 04:00:17 +00002620
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002621void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002622 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002623 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002624
2625 while (iter.next()) {
2626 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002627 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002628 }
2629
2630 LOOPER_END
2631}
2632
dandovb3c9d1c2014-08-12 08:34:29 -07002633void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002634 const SkPoint texCoords[4], SkBlendMode bmode,
2635 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002636 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002637 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002638 return;
2639 }
mtklein6cfa73a2014-08-13 13:33:49 -07002640
Mike Reedfaba3712016-11-03 14:45:31 -04002641 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002642}
2643
2644void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002645 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002646 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002647 // Since a patch is always within the convex hull of the control points, we discard it when its
2648 // bounding rectangle is completely outside the current clip.
2649 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002650 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002651 if (this->quickReject(bounds)) {
2652 return;
2653 }
mtklein6cfa73a2014-08-13 13:33:49 -07002654
Ben Wagner2c312c42018-06-27 14:46:46 -04002655 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002656
dandovecfff212014-08-04 10:02:00 -07002657 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002658 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002659 }
mtklein6cfa73a2014-08-13 13:33:49 -07002660
dandovecfff212014-08-04 10:02:00 -07002661 LOOPER_END
2662}
2663
reeda8db7282015-07-07 10:22:31 -07002664void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002665#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002666 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002667#endif
reede3b38ce2016-01-08 09:18:44 -08002668 RETURN_ON_NULL(dr);
2669 if (x || y) {
2670 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2671 this->onDrawDrawable(dr, &matrix);
2672 } else {
2673 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002674 }
2675}
2676
reeda8db7282015-07-07 10:22:31 -07002677void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002678#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002679 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002680#endif
reede3b38ce2016-01-08 09:18:44 -08002681 RETURN_ON_NULL(dr);
2682 if (matrix && matrix->isIdentity()) {
2683 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002684 }
reede3b38ce2016-01-08 09:18:44 -08002685 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002686}
2687
2688void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002689 // drawable bounds are no longer reliable (e.g. android displaylist)
2690 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002691 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002692}
2693
reed71c3c762015-06-24 10:29:17 -07002694void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002695 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002696 const SkRect* cull, const SkPaint* paint) {
2697 if (cull && this->quickReject(*cull)) {
2698 return;
2699 }
2700
2701 SkPaint pnt;
2702 if (paint) {
2703 pnt = *paint;
2704 }
halcanary9d524f22016-03-29 09:03:52 -07002705
Ben Wagner2c312c42018-06-27 14:46:46 -04002706 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002707 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002708 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002709 }
2710 LOOPER_END
2711}
2712
reedf70b5312016-03-04 16:36:20 -08002713void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2714 SkASSERT(key);
2715
2716 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002717 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002718 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002719 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002720 }
2721 LOOPER_END
2722}
2723
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002724void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2725 SkColor color, SkBlendMode mode) {
2726 SkASSERT(r.isSorted());
2727
2728 // If this used a paint, it would be a filled color with blend mode, which does not
2729 // need to use an autodraw loop, so use SkDrawIter directly.
2730 if (this->quickReject(r)) {
2731 return;
2732 }
2733
2734 this->predrawNotify();
2735 SkDrawIter iter(this);
2736 while(iter.next()) {
2737 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2738 }
2739}
2740
2741void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2742 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2743 const SkPaint* paint, SrcRectConstraint constraint) {
2744 SkPaint realPaint;
2745 init_image_paint(&realPaint, paint);
2746
2747 // Looper is used when there are image filters, which drawEdgeAAImageSet needs to support
2748 // for Chromium's RenderPassDrawQuads' filters.
2749 LOOPER_BEGIN(realPaint, nullptr)
2750 while (iter.next()) {
2751 iter.fDevice->drawEdgeAAImageSet(
2752 imageSet, count, dstClips, preViewMatrices, looper.paint(), constraint);
2753 }
2754 LOOPER_END
2755}
2756
reed@android.com8a1c16f2008-12-17 15:59:43 +00002757//////////////////////////////////////////////////////////////////////////////
2758// These methods are NOT virtual, and therefore must call back into virtual
2759// methods, rather than actually drawing themselves.
2760//////////////////////////////////////////////////////////////////////////////
2761
reed374772b2016-10-05 17:33:02 -07002762void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002763 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002765 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766 this->drawPaint(paint);
2767}
2768
2769void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002770 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002771 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2772}
2773
Mike Reed3661bc92017-02-22 13:21:42 -05002774void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776 pts[0].set(x0, y0);
2777 pts[1].set(x1, y1);
2778 this->drawPoints(kLines_PointMode, 2, pts, paint);
2779}
2780
Mike Reed3661bc92017-02-22 13:21:42 -05002781void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782 if (radius < 0) {
2783 radius = 0;
2784 }
2785
2786 SkRect r;
2787 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002788 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002789}
2790
2791void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2792 const SkPaint& paint) {
2793 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002794 SkRRect rrect;
2795 rrect.setRectXY(r, rx, ry);
2796 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002797 } else {
2798 this->drawRect(r, paint);
2799 }
2800}
2801
reed@android.com8a1c16f2008-12-17 15:59:43 +00002802void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2803 SkScalar sweepAngle, bool useCenter,
2804 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002805 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002806 if (oval.isEmpty() || !sweepAngle) {
2807 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002808 }
bsalomon21af9ca2016-08-25 12:29:23 -07002809 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002810}
2811
reed@android.comf76bacf2009-05-13 14:00:33 +00002812///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002813#ifdef SK_DISABLE_SKPICTURE
2814void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002815
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002816
2817void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2818 const SkPaint* paint) {}
2819#else
Mike Klein88d90712018-01-27 17:30:04 +00002820/**
2821 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2822 * against the playback cost of recursing into the subpicture to get at its actual ops.
2823 *
2824 * For now we pick a conservatively small value, though measurement (and other heuristics like
2825 * the type of ops contained) may justify changing this value.
2826 */
2827#define kMaxPictureOpsToUnrollInsteadOfRef 1
2828
reedd5fa1a42014-08-09 11:08:05 -07002829void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002830 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002831 RETURN_ON_NULL(picture);
2832
reede3b38ce2016-01-08 09:18:44 -08002833 if (matrix && matrix->isIdentity()) {
2834 matrix = nullptr;
2835 }
Mike Klein88d90712018-01-27 17:30:04 +00002836 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2837 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2838 picture->playback(this);
2839 } else {
2840 this->onDrawPicture(picture, matrix, paint);
2841 }
reedd5fa1a42014-08-09 11:08:05 -07002842}
robertphillips9b14f262014-06-04 05:40:44 -07002843
reedd5fa1a42014-08-09 11:08:05 -07002844void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2845 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002846 if (!paint || paint->canComputeFastBounds()) {
2847 SkRect bounds = picture->cullRect();
2848 if (paint) {
2849 paint->computeFastBounds(bounds, &bounds);
2850 }
2851 if (matrix) {
2852 matrix->mapRect(&bounds);
2853 }
2854 if (this->quickReject(bounds)) {
2855 return;
2856 }
2857 }
2858
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002859 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002860 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002861}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002862#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002863
reed@android.com8a1c16f2008-12-17 15:59:43 +00002864///////////////////////////////////////////////////////////////////////////////
2865///////////////////////////////////////////////////////////////////////////////
2866
reed3aafe112016-08-18 12:45:34 -07002867SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002868 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002869
2870 SkASSERT(canvas);
2871
reed3aafe112016-08-18 12:45:34 -07002872 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002873 fDone = !fImpl->next();
2874}
2875
2876SkCanvas::LayerIter::~LayerIter() {
2877 fImpl->~SkDrawIter();
2878}
2879
2880void SkCanvas::LayerIter::next() {
2881 fDone = !fImpl->next();
2882}
2883
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002884SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002885 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002886}
2887
2888const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002889 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002890}
2891
2892const SkPaint& SkCanvas::LayerIter::paint() const {
2893 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002894 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002895 paint = &fDefaultPaint;
2896 }
2897 return *paint;
2898}
2899
Mike Reedca37f322018-03-08 13:22:16 -05002900SkIRect SkCanvas::LayerIter::clipBounds() const {
2901 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002902}
2903
reed@android.com8a1c16f2008-12-17 15:59:43 +00002904int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2905int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002906
2907///////////////////////////////////////////////////////////////////////////////
2908
Brian Osmane8a98632019-04-10 10:26:10 -04002909SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2910SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2911SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2912SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2913
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002914SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2915 const SkRect& dstRect, int matrixIndex, float alpha,
2916 unsigned aaFlags, bool hasClip)
2917 : fImage(std::move(image))
2918 , fSrcRect(srcRect)
2919 , fDstRect(dstRect)
2920 , fMatrixIndex(matrixIndex)
2921 , fAlpha(alpha)
2922 , fAAFlags(aaFlags)
2923 , fHasClip(hasClip) {}
2924
2925SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2926 const SkRect& dstRect, float alpha, unsigned aaFlags)
2927 : fImage(std::move(image))
2928 , fSrcRect(srcRect)
2929 , fDstRect(dstRect)
2930 , fAlpha(alpha)
2931 , fAAFlags(aaFlags) {}
2932
2933///////////////////////////////////////////////////////////////////////////////
2934
Mike Reed5df49342016-11-12 08:06:55 -06002935std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002936 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002937 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002938 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002939 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002940
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002941 SkBitmap bitmap;
2942 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002943 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002944 }
Mike Reed12f77342017-11-08 11:19:52 -05002945
2946 return props ?
2947 skstd::make_unique<SkCanvas>(bitmap, *props) :
2948 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002949}
reedd5fa1a42014-08-09 11:08:05 -07002950
2951///////////////////////////////////////////////////////////////////////////////
2952
Florin Malitaee424ac2016-12-01 12:47:59 -05002953SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002954 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002955
Florin Malita439ace92016-12-02 12:05:41 -05002956SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002957 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002958
Herb Derbyefe39bc2018-05-01 17:06:20 -04002959SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002960 : INHERITED(device) {}
2961
Florin Malitaee424ac2016-12-01 12:47:59 -05002962SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2963 (void)this->INHERITED::getSaveLayerStrategy(rec);
2964 return kNoLayer_SaveLayerStrategy;
2965}
2966
Mike Reed148b7fd2018-12-18 17:38:18 -05002967bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2968 return false;
2969}
2970
Florin Malitaee424ac2016-12-01 12:47:59 -05002971///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002972
reed73603f32016-09-20 08:42:38 -07002973static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2974static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2975static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2976static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2977static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2978static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002979
2980///////////////////////////////////////////////////////////////////////////////////////////////////
2981
2982SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2983 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002984 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002985 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2986 SkIPoint origin = dev->getOrigin();
2987 SkMatrix ctm = this->getTotalMatrix();
2988 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2989
2990 SkIRect clip = fMCRec->fRasterClip.getBounds();
2991 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002992 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002993 clip.setEmpty();
2994 }
2995
2996 fAllocator->updateHandle(handle, ctm, clip);
2997 return handle;
2998 }
2999 return nullptr;
3000}
3001
3002static bool install(SkBitmap* bm, const SkImageInfo& info,
3003 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04003004 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05003005}
3006
3007SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3008 SkBitmap* bm) {
3009 SkRasterHandleAllocator::Rec rec;
3010 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3011 return nullptr;
3012 }
3013 return rec.fHandle;
3014}
3015
3016std::unique_ptr<SkCanvas>
3017SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3018 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04003019 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05003020 return nullptr;
3021 }
3022
3023 SkBitmap bm;
3024 Handle hndl;
3025
3026 if (rec) {
3027 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3028 } else {
3029 hndl = alloc->allocBitmap(info, &bm);
3030 }
3031 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3032}
Mike Reed7c9c9e42018-01-03 09:23:34 -05003033
3034///////////////////////////////////////////////////////////////////////////////////////////////////
3035
3036