blob: 8d8e07c7e2f0d9b1f9873fc81a2b43bebf807a0c [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 Malita07e4adf2019-01-07 16:34:18 -05001084 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType();
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 Reed356f7c22017-01-10 11:58:39 -05001089 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001090 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001091 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001092 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1093 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001094 return;
reed61f501f2015-04-29 08:34:00 -07001095 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001096 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001097 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098
Mike Reedb43a3e02017-02-11 10:18:58 -05001099 // only have a "next" if this new layer doesn't affect the clip (rare)
1100 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101 fMCRec->fLayer = layer;
1102 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001103
Mike Reedc61abee2017-02-28 17:45:27 -05001104 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001105 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001106 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001107 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001108
Mike Reedc42a1cd2017-02-14 14:25:14 -05001109 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1110
1111 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1112 if (layer->fNext) {
1113 // need to punch a hole in the previous device, so we don't draw there, given that
1114 // the new top-layer will allow drawing to happen "below" it.
1115 SkRegion hole(ir);
1116 do {
1117 layer = layer->fNext;
1118 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1119 } while (layer->fNext);
1120 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001121}
1122
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001123int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001124 if (0xFF == alpha) {
1125 return this->saveLayer(bounds, nullptr);
1126 } else {
1127 SkPaint tmpPaint;
1128 tmpPaint.setAlpha(alpha);
1129 return this->saveLayer(bounds, &tmpPaint);
1130 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001131}
1132
Mike Reed148b7fd2018-12-18 17:38:18 -05001133void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1134 SkIRect devBounds;
1135 if (localBounds) {
1136 SkRect tmp;
1137 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1138 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1139 devBounds.setEmpty();
1140 }
1141 } else {
1142 devBounds = this->getDeviceClipBounds();
1143 }
1144 if (devBounds.isEmpty()) {
1145 return;
1146 }
1147
1148 SkBaseDevice* device = this->getTopDevice();
1149 if (nullptr == device) { // Do we still need this check???
1150 return;
1151 }
1152
1153 // need the bounds relative to the device itself
1154 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1155
1156 auto backImage = device->snapBackImage(devBounds);
1157 if (!backImage) {
1158 return;
1159 }
1160
1161 // we really need the save, so we can wack the fMCRec
1162 this->checkForDeferredSave();
1163
1164 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1165
1166 SkPaint paint;
1167 paint.setBlendMode(SkBlendMode::kClear);
Mike Reed9adc82c2019-04-23 10:28:13 -04001168 this->drawClippedToSaveBehind(paint);
Mike Reed148b7fd2018-12-18 17:38:18 -05001169}
1170
reed@android.com8a1c16f2008-12-17 15:59:43 +00001171void SkCanvas::internalRestore() {
1172 SkASSERT(fMCStack.count() != 0);
1173
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001174 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001175 DeviceCM* layer = fMCRec->fLayer; // may be null
1176 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001177 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001178
Mike Reed148b7fd2018-12-18 17:38:18 -05001179 // move this out before we do the actual restore
1180 auto backImage = std::move(fMCRec->fBackImage);
1181
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182 // now do the normal restore()
1183 fMCRec->~MCRec(); // balanced in save()
1184 fMCStack.pop_back();
1185 fMCRec = (MCRec*)fMCStack.back();
1186
Mike Reedc42a1cd2017-02-14 14:25:14 -05001187 if (fMCRec) {
1188 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1189 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001190
Mike Reed148b7fd2018-12-18 17:38:18 -05001191 if (backImage) {
1192 SkPaint paint;
1193 paint.setBlendMode(SkBlendMode::kDstOver);
1194 const int x = backImage->fLoc.x();
1195 const int y = backImage->fLoc.y();
1196 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1197 nullptr, SkMatrix::I());
1198 }
1199
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1201 since if we're being recorded, we don't want to record this (the
1202 recorder will have already recorded the restore).
1203 */
bsalomon49f085d2014-09-05 13:34:00 -07001204 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001205 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001206 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001207 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001208 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001209 layer->fPaint.get(),
1210 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001211 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001212 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001213 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001214 delete layer;
reedb679ca82015-04-07 04:40:48 -07001215 } else {
1216 // we're at the root
reeda499f902015-05-01 09:34:31 -07001217 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001218 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001219 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001221 }
msarettfbfa2582016-08-12 08:29:08 -07001222
1223 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001224 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001225 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1226 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001227}
1228
reede8f30622016-03-23 18:59:25 -07001229sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001230 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001231 props = &fProps;
1232 }
1233 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001234}
1235
reede8f30622016-03-23 18:59:25 -07001236sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001237 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001238 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001239}
1240
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001241SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001242 return this->onImageInfo();
1243}
1244
1245SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001246 SkBaseDevice* dev = this->getDevice();
1247 if (dev) {
1248 return dev->imageInfo();
1249 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001250 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001251 }
1252}
1253
brianosman898235c2016-04-06 07:38:23 -07001254bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001255 return this->onGetProps(props);
1256}
1257
1258bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001259 SkBaseDevice* dev = this->getDevice();
1260 if (dev) {
1261 if (props) {
1262 *props = fProps;
1263 }
1264 return true;
1265 } else {
1266 return false;
1267 }
1268}
1269
reed6ceeebd2016-03-09 14:26:26 -08001270bool SkCanvas::peekPixels(SkPixmap* pmap) {
1271 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001272}
1273
reed884e97c2015-05-26 11:31:54 -07001274bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001275 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001276 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001277}
1278
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001279void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001280 SkPixmap pmap;
1281 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001282 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001283 }
1284 if (info) {
1285 *info = pmap.info();
1286 }
1287 if (rowBytes) {
1288 *rowBytes = pmap.rowBytes();
1289 }
1290 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001291 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001292 }
reed884e97c2015-05-26 11:31:54 -07001293 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001294}
1295
reed884e97c2015-05-26 11:31:54 -07001296bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001297 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001298 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001299}
1300
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302
Mike Reed8bcd1282019-03-13 16:51:54 -04001303// In our current design/features, we should never have a layer (src) in a different colorspace
1304// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1305// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1306// colorspace.
1307static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1308 SkASSERT(src == dst);
1309}
1310
Florin Malita53f77bd2017-04-28 13:48:37 -04001311void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1312 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001314 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315 paint = &tmp;
1316 }
reed@google.com4b226022011-01-11 18:32:13 +00001317
Ben Wagner2c312c42018-06-27 14:46:46 -04001318 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001319
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001321 SkBaseDevice* dstDev = iter.fDevice;
Mike Reed8bcd1282019-03-13 16:51:54 -04001322 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1323 srcDev->imageInfo().colorSpace());
reed@google.com76dd2772012-01-05 21:15:07 +00001324 paint = &looper.paint();
1325 SkImageFilter* filter = paint->getImageFilter();
1326 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001327 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001328 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1329 if (specialImage) {
Mike Reed8bcd1282019-03-13 16:51:54 -04001330 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1331 specialImage->getColorSpace());
Florin Malita53f77bd2017-04-28 13:48:37 -04001332 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1333 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001334 }
reed@google.com76dd2772012-01-05 21:15:07 +00001335 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001336 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001337 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338 }
reeda2217ef2016-07-20 06:04:34 -07001339
reed@google.com4e2b3d32011-04-07 14:18:59 +00001340 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341}
1342
reed32704672015-12-16 08:27:10 -08001343/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001344
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001345void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001346 if (dx || dy) {
1347 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001348 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001349
reedfe69b502016-09-12 06:31:48 -07001350 // Translate shouldn't affect the is-scale-translateness of the matrix.
1351 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001352
Mike Reedc42a1cd2017-02-14 14:25:14 -05001353 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001354
reedfe69b502016-09-12 06:31:48 -07001355 this->didTranslate(dx,dy);
1356 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001357}
1358
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001359void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001360 SkMatrix m;
1361 m.setScale(sx, sy);
1362 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001363}
1364
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001365void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001366 SkMatrix m;
1367 m.setRotate(degrees);
1368 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001369}
1370
bungeman7438bfc2016-07-12 15:01:19 -07001371void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1372 SkMatrix m;
1373 m.setRotate(degrees, px, py);
1374 this->concat(m);
1375}
1376
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001377void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001378 SkMatrix m;
1379 m.setSkew(sx, sy);
1380 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001381}
1382
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001383void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001384 if (matrix.isIdentity()) {
1385 return;
1386 }
1387
reed2ff1fce2014-12-11 07:07:37 -08001388 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001389 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001390 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001391
Mike Reed7627fa52017-02-08 10:07:53 -05001392 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001393
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001394 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001395}
1396
reed8c30a812016-04-20 16:36:51 -07001397void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001398 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001399 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001400
Mike Reedc42a1cd2017-02-14 14:25:14 -05001401 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001402}
1403
1404void SkCanvas::setMatrix(const SkMatrix& matrix) {
1405 this->checkForDeferredSave();
1406 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001407 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408}
1409
reed@android.com8a1c16f2008-12-17 15:59:43 +00001410void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001411 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412}
1413
1414//////////////////////////////////////////////////////////////////////////////
1415
Mike Reedc1f77742016-12-09 09:00:50 -05001416void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001417 if (!rect.isFinite()) {
1418 return;
1419 }
reed2ff1fce2014-12-11 07:07:37 -08001420 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001421 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1422 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001423}
1424
Mike Reedc1f77742016-12-09 09:00:50 -05001425void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001426 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001427
Mike Reed7627fa52017-02-08 10:07:53 -05001428 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001429
reedc64eff52015-11-21 12:39:45 -08001430 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001431 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1432 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001433 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434}
1435
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001436void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1437 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001438 if (fClipRestrictionRect.isEmpty()) {
1439 // we notify the device, but we *dont* resolve deferred saves (since we're just
1440 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001441 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001442 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001443 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001444 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001445 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001446 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001447 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1448 }
1449}
1450
Mike Reedc1f77742016-12-09 09:00:50 -05001451void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001452 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001453 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001454 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001455 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1456 } else {
1457 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001458 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001459}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001460
Mike Reedc1f77742016-12-09 09:00:50 -05001461void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001462 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001463
Brian Salomona3b45d42016-10-03 11:36:16 -04001464 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001465
Mike Reed7627fa52017-02-08 10:07:53 -05001466 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001467
Mike Reed20800c82017-11-15 16:09:04 -05001468 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1469 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001470 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001471}
1472
Mike Reedc1f77742016-12-09 09:00:50 -05001473void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001474 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001475 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001476
1477 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1478 SkRect r;
1479 if (path.isRect(&r)) {
1480 this->onClipRect(r, op, edgeStyle);
1481 return;
1482 }
1483 SkRRect rrect;
1484 if (path.isOval(&r)) {
1485 rrect.setOval(r);
1486 this->onClipRRect(rrect, op, edgeStyle);
1487 return;
1488 }
1489 if (path.isRRect(&rrect)) {
1490 this->onClipRRect(rrect, op, edgeStyle);
1491 return;
1492 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001493 }
robertphillips39f05382015-11-24 09:30:12 -08001494
1495 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001496}
1497
Mike Reedc1f77742016-12-09 09:00:50 -05001498void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001499 AutoValidateClip avc(this);
1500
Brian Salomona3b45d42016-10-03 11:36:16 -04001501 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001502
Mike Reed7627fa52017-02-08 10:07:53 -05001503 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001504
Brian Salomona3b45d42016-10-03 11:36:16 -04001505 const SkPath* rasterClipPath = &path;
1506 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001507 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1508 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001509 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001510}
1511
Mike Reedc1f77742016-12-09 09:00:50 -05001512void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001513 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001514 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001515}
1516
Mike Reedc1f77742016-12-09 09:00:50 -05001517void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001518 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001519
reed@google.com5c3d1472011-02-22 19:12:23 +00001520 AutoValidateClip avc(this);
1521
Mike Reed20800c82017-11-15 16:09:04 -05001522 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001523 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001524}
1525
reed@google.com819c9212011-02-23 18:56:55 +00001526#ifdef SK_DEBUG
1527void SkCanvas::validateClip() const {
1528 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001529 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001530 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001531 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001532 return;
1533 }
reed@google.com819c9212011-02-23 18:56:55 +00001534}
1535#endif
1536
Mike Reeda1361362017-03-07 09:37:29 -05001537bool SkCanvas::androidFramework_isClipAA() const {
1538 bool containsAA = false;
1539
1540 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1541
1542 return containsAA;
1543}
1544
1545class RgnAccumulator {
1546 SkRegion* fRgn;
1547public:
1548 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1549 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1550 SkIPoint origin = device->getOrigin();
1551 if (origin.x() | origin.y()) {
1552 rgn->translate(origin.x(), origin.y());
1553 }
1554 fRgn->op(*rgn, SkRegion::kUnion_Op);
1555 }
1556};
1557
1558void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1559 RgnAccumulator accum(rgn);
1560 SkRegion tmp;
1561
1562 rgn->setEmpty();
1563 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001564}
1565
reed@google.com5c3d1472011-02-22 19:12:23 +00001566///////////////////////////////////////////////////////////////////////////////
1567
reed@google.com754de5f2014-02-24 19:38:20 +00001568bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001569 return fMCRec->fRasterClip.isEmpty();
1570
1571 // TODO: should we only use the conservative answer in a recording canvas?
1572#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001573 SkBaseDevice* dev = this->getTopDevice();
1574 // if no device we return true
1575 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001576#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001577}
1578
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001579bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001580 SkBaseDevice* dev = this->getTopDevice();
1581 // if no device we return false
1582 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001583}
1584
msarettfbfa2582016-08-12 08:29:08 -07001585static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1586#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1587 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1588 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1589 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1590 return 0xF != _mm_movemask_ps(mask);
1591#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1592 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1593 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1594 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1595 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1596#else
1597 SkRect devRectAsRect;
1598 SkRect devClipAsRect;
1599 devRect.store(&devRectAsRect.fLeft);
1600 devClip.store(&devClipAsRect.fLeft);
1601 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1602#endif
1603}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001604
msarettfbfa2582016-08-12 08:29:08 -07001605// It's important for this function to not be inlined. Otherwise the compiler will share code
1606// between the fast path and the slow path, resulting in two slow paths.
1607static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1608 const SkMatrix& matrix) {
1609 SkRect deviceRect;
1610 matrix.mapRect(&deviceRect, src);
1611 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1612}
1613
1614bool SkCanvas::quickReject(const SkRect& src) const {
1615#ifdef SK_DEBUG
1616 // Verify that fDeviceClipBounds are set properly.
1617 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001618 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001619 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001620 } else {
msarettfbfa2582016-08-12 08:29:08 -07001621 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001622 }
msarettfbfa2582016-08-12 08:29:08 -07001623
msarett9637ea92016-08-18 14:03:30 -07001624 // Verify that fIsScaleTranslate is set properly.
1625 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001626#endif
1627
msarett9637ea92016-08-18 14:03:30 -07001628 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001629 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1630 }
1631
1632 // We inline the implementation of mapScaleTranslate() for the fast path.
1633 float sx = fMCRec->fMatrix.getScaleX();
1634 float sy = fMCRec->fMatrix.getScaleY();
1635 float tx = fMCRec->fMatrix.getTranslateX();
1636 float ty = fMCRec->fMatrix.getTranslateY();
1637 Sk4f scale(sx, sy, sx, sy);
1638 Sk4f trans(tx, ty, tx, ty);
1639
1640 // Apply matrix.
1641 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1642
1643 // Make sure left < right, top < bottom.
1644 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1645 Sk4f min = Sk4f::Min(ltrb, rblt);
1646 Sk4f max = Sk4f::Max(ltrb, rblt);
1647 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1648 // ARM this sequence generates the fastest (a single instruction).
1649 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1650
1651 // Check if the device rect is NaN or outside the clip.
1652 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001653}
1654
reed@google.com3b3e8952012-08-16 20:53:31 +00001655bool SkCanvas::quickReject(const SkPath& path) const {
1656 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657}
1658
Mike Klein83c8dd92017-11-28 17:08:45 -05001659SkRect SkCanvas::getLocalClipBounds() const {
1660 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001661 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001662 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001663 }
1664
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001665 SkMatrix inverse;
1666 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001667 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001668 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001669 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001670
Mike Reed42e8c532017-01-23 14:09:13 -05001671 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001672 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001673 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001674
Mike Reedb57b9312018-04-23 12:12:54 -04001675 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001676 inverse.mapRect(&bounds, r);
1677 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001678}
1679
Mike Klein83c8dd92017-11-28 17:08:45 -05001680SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001681 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001682}
1683
reed@android.com8a1c16f2008-12-17 15:59:43 +00001684const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001685 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001686}
1687
Brian Osman11052242016-10-27 14:47:55 -04001688GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001689 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001690 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001691}
1692
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001693GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001694 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001695 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001696}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001697
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001698void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1699 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001700 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001701 if (outer.isEmpty()) {
1702 return;
1703 }
1704 if (inner.isEmpty()) {
1705 this->drawRRect(outer, paint);
1706 return;
1707 }
1708
1709 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001710 // be able to return ...
1711 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001712 //
1713 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001714 if (!outer.getBounds().contains(inner.getBounds())) {
1715 return;
1716 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001717
1718 this->onDrawDRRect(outer, inner, paint);
1719}
1720
reed41af9662015-01-05 07:49:08 -08001721void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001722 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001723 this->onDrawPaint(paint);
1724}
1725
1726void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001727 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001728 // To avoid redundant logic in our culling code and various backends, we always sort rects
1729 // before passing them along.
1730 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001731}
1732
Mike Reedd5674082019-04-19 15:00:47 -04001733void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1734 TRACE_EVENT0("skia", TRACE_FUNC);
1735 this->onDrawBehind(paint);
1736}
1737
msarettdca352e2016-08-26 06:37:45 -07001738void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001739 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001740 if (region.isEmpty()) {
1741 return;
1742 }
1743
1744 if (region.isRect()) {
1745 return this->drawIRect(region.getBounds(), paint);
1746 }
1747
1748 this->onDrawRegion(region, paint);
1749}
1750
reed41af9662015-01-05 07:49:08 -08001751void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001752 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001753 // To avoid redundant logic in our culling code and various backends, we always sort rects
1754 // before passing them along.
1755 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001756}
1757
1758void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001759 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001760 this->onDrawRRect(rrect, paint);
1761}
1762
1763void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001764 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001765 this->onDrawPoints(mode, count, pts, paint);
1766}
1767
Mike Reede88a1cb2017-03-17 09:50:46 -04001768void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1769 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001770 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001771 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001772 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1773 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001774 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001775}
1776
1777void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001778 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001779 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001780 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1781}
1782
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001783void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1784 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001785 TRACE_EVENT0("skia", TRACE_FUNC);
1786 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001787 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001788 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1789}
1790
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001791void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1792 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001793 TRACE_EVENT0("skia", TRACE_FUNC);
1794 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001795 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001796 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001797}
1798
1799void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001800 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001801 this->onDrawPath(path, paint);
1802}
1803
reeda85d4d02015-05-06 12:56:48 -07001804void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001805 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001806 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001807 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001808}
1809
Mike Reedc4e31092018-01-30 11:15:27 -05001810// Returns true if the rect can be "filled" : non-empty and finite
1811static bool fillable(const SkRect& r) {
1812 SkScalar w = r.width();
1813 SkScalar h = r.height();
1814 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1815}
1816
reede47829b2015-08-06 10:02:53 -07001817void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1818 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001819 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001820 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001821 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001822 return;
1823 }
1824 this->onDrawImageRect(image, &src, dst, paint, constraint);
1825}
reed41af9662015-01-05 07:49:08 -08001826
reed84984ef2015-07-17 07:09:43 -07001827void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1828 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001829 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001830 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001831}
1832
Brian Salomonf08002c2018-10-26 16:15:46 -04001833void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001834 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001835 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001836 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001837}
reede47829b2015-08-06 10:02:53 -07001838
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001839namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001840class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001841public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001842 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1843 if (!origPaint) {
1844 return;
1845 }
1846 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1847 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1848 }
1849 if (origPaint->getMaskFilter()) {
1850 fPaint.writable()->setMaskFilter(nullptr);
1851 }
1852 if (origPaint->isAntiAlias()) {
1853 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001854 }
1855 }
1856
1857 const SkPaint* get() const {
1858 return fPaint;
1859 }
1860
1861private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001862 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001863};
1864} // namespace
1865
reed4c21dc52015-06-25 12:32:03 -07001866void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1867 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001868 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001869 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001870 if (dst.isEmpty()) {
1871 return;
1872 }
msarett552bca92016-08-03 06:53:26 -07001873 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001874 LatticePaint latticePaint(paint);
1875 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001876 } else {
reede47829b2015-08-06 10:02:53 -07001877 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001878 }
reed4c21dc52015-06-25 12:32:03 -07001879}
1880
msarett16882062016-08-16 09:31:08 -07001881void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1882 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001883 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001884 RETURN_ON_NULL(image);
1885 if (dst.isEmpty()) {
1886 return;
1887 }
msarett71df2d72016-09-30 12:41:42 -07001888
1889 SkIRect bounds;
1890 Lattice latticePlusBounds = lattice;
1891 if (!latticePlusBounds.fBounds) {
1892 bounds = SkIRect::MakeWH(image->width(), image->height());
1893 latticePlusBounds.fBounds = &bounds;
1894 }
1895
1896 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001897 LatticePaint latticePaint(paint);
1898 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001899 } else {
1900 this->drawImageRect(image, dst, paint);
1901 }
1902}
1903
reed41af9662015-01-05 07:49:08 -08001904void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001905 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001906 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001907 return;
1908 }
reed41af9662015-01-05 07:49:08 -08001909 this->onDrawBitmap(bitmap, dx, dy, paint);
1910}
1911
reede47829b2015-08-06 10:02:53 -07001912void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001913 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001914 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001915 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001916 return;
1917 }
reede47829b2015-08-06 10:02:53 -07001918 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001919}
1920
reed84984ef2015-07-17 07:09:43 -07001921void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1922 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001923 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001924}
1925
reede47829b2015-08-06 10:02:53 -07001926void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1927 SrcRectConstraint constraint) {
1928 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1929 constraint);
1930}
reede47829b2015-08-06 10:02:53 -07001931
reed41af9662015-01-05 07:49:08 -08001932void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1933 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001934 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001935 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001936 return;
1937 }
msarett552bca92016-08-03 06:53:26 -07001938 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001939 LatticePaint latticePaint(paint);
1940 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001941 } else {
reeda5517e22015-07-14 10:54:12 -07001942 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001943 }
reed41af9662015-01-05 07:49:08 -08001944}
1945
msarettc573a402016-08-02 08:05:56 -07001946void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1947 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001948 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001949 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001950 return;
1951 }
msarett71df2d72016-09-30 12:41:42 -07001952
1953 SkIRect bounds;
1954 Lattice latticePlusBounds = lattice;
1955 if (!latticePlusBounds.fBounds) {
1956 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1957 latticePlusBounds.fBounds = &bounds;
1958 }
1959
1960 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001961 LatticePaint latticePaint(paint);
1962 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001963 } else {
msarett16882062016-08-16 09:31:08 -07001964 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001965 }
msarettc573a402016-08-02 08:05:56 -07001966}
1967
reed71c3c762015-06-24 10:29:17 -07001968void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001969 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001970 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001971 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001972 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001973 if (count <= 0) {
1974 return;
1975 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001976 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001977 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001978 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001979}
1980
reedf70b5312016-03-04 16:36:20 -08001981void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001982 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001983 if (key) {
1984 this->onDrawAnnotation(rect, key, value);
1985 }
1986}
1987
reede47829b2015-08-06 10:02:53 -07001988void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1989 const SkPaint* paint, SrcRectConstraint constraint) {
1990 if (src) {
1991 this->drawImageRect(image, *src, dst, paint, constraint);
1992 } else {
1993 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1994 dst, paint, constraint);
1995 }
1996}
1997void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1998 const SkPaint* paint, SrcRectConstraint constraint) {
1999 if (src) {
2000 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2001 } else {
2002 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2003 dst, paint, constraint);
2004 }
2005}
2006
Mike Reed4204da22017-05-17 08:53:36 -04002007void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002008 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04002009 this->onDrawShadowRec(path, rec);
2010}
2011
2012void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
2013 SkPaint paint;
2014 const SkRect& pathBounds = path.getBounds();
2015
Ben Wagner2c312c42018-06-27 14:46:46 -04002016 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04002017 while (iter.next()) {
2018 iter.fDevice->drawShadow(path, rec);
2019 }
2020 LOOPER_END
2021}
2022
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002023void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2024 QuadAAFlags aaFlags, SkColor color, SkBlendMode mode) {
2025 TRACE_EVENT0("skia", TRACE_FUNC);
2026 // Make sure the rect is sorted before passing it along
2027 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2028}
2029
2030void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2031 const SkPoint dstClips[],
2032 const SkMatrix preViewMatrices[],
2033 const SkPaint* paint,
2034 SrcRectConstraint constraint) {
2035 TRACE_EVENT0("skia", TRACE_FUNC);
2036 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2037}
2038
reed@android.com8a1c16f2008-12-17 15:59:43 +00002039//////////////////////////////////////////////////////////////////////////////
2040// These are the virtual drawing methods
2041//////////////////////////////////////////////////////////////////////////////
2042
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002043void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002044 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002045 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2046 }
2047}
2048
reed41af9662015-01-05 07:49:08 -08002049void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002050 this->internalDrawPaint(paint);
2051}
2052
2053void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002054 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002055
2056 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002057 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002058 }
2059
reed@google.com4e2b3d32011-04-07 14:18:59 +00002060 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002061}
2062
reed41af9662015-01-05 07:49:08 -08002063void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2064 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002065 if ((long)count <= 0) {
2066 return;
2067 }
2068
Mike Reed822128b2017-02-28 16:41:03 -05002069 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002070 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002071 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002072 // special-case 2 points (common for drawing a single line)
2073 if (2 == count) {
2074 r.set(pts[0], pts[1]);
2075 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002076 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002077 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002078 if (!r.isFinite()) {
2079 return;
2080 }
Mike Reed822128b2017-02-28 16:41:03 -05002081 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002082 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2083 return;
2084 }
2085 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002086 }
reed@google.coma584aed2012-05-16 14:06:02 +00002087
halcanary96fcdcc2015-08-27 07:41:13 -07002088 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002089
Ben Wagner2c312c42018-06-27 14:46:46 -04002090 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002091
reed@android.com8a1c16f2008-12-17 15:59:43 +00002092 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002093 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002094 }
reed@google.com4b226022011-01-11 18:32:13 +00002095
reed@google.com4e2b3d32011-04-07 14:18:59 +00002096 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002097}
2098
reed4a167172016-08-18 17:15:25 -07002099static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
Mike Reed9dc0b9e2019-07-29 17:52:48 -04002100 return paint.getImageFilter() != nullptr;
reed4a167172016-08-18 17:15:25 -07002101}
2102
reed41af9662015-01-05 07:49:08 -08002103void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002104 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002105 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002106 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002107 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002108 return;
2109 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002110 }
reed@google.com4b226022011-01-11 18:32:13 +00002111
reed4a167172016-08-18 17:15:25 -07002112 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002113 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002114
reed4a167172016-08-18 17:15:25 -07002115 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002116 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002117 }
2118
2119 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002120 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002121 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002122 SkDrawIter iter(this);
2123 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002124 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002125 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002126 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002127}
2128
msarett44df6512016-08-25 13:54:30 -07002129void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002130 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002131 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002132 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002133 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2134 return;
2135 }
msarett44df6512016-08-25 13:54:30 -07002136 }
2137
Ben Wagner2c312c42018-06-27 14:46:46 -04002138 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002139
2140 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002141 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002142 }
2143
2144 LOOPER_END
2145}
2146
Mike Reedd5674082019-04-19 15:00:47 -04002147void SkCanvas::onDrawBehind(const SkPaint& paint) {
2148 SkIRect bounds;
2149 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2150 for (;;) {
2151 const MCRec* rec = (const MCRec*)iter.prev();
2152 if (!rec) {
2153 return; // no backimages, so nothing to draw
2154 }
2155 if (rec->fBackImage) {
2156 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2157 rec->fBackImage->fImage->width(),
2158 rec->fBackImage->fImage->height());
2159 break;
2160 }
2161 }
2162
2163 LOOPER_BEGIN(paint, nullptr)
2164
2165 while (iter.next()) {
2166 SkBaseDevice* dev = iter.fDevice;
2167
Mike Reedd5674082019-04-19 15:00:47 -04002168 dev->save();
2169 // We use clipRegion because it is already defined to operate in dev-space
2170 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2171 // but we don't want that, so we undo that before calling in.
2172 SkRegion rgn(bounds.makeOffset(dev->fOrigin.fX, dev->fOrigin.fY));
2173 dev->clipRegion(rgn, SkClipOp::kIntersect);
2174 dev->drawPaint(looper.paint());
Mike Reed9adc82c2019-04-23 10:28:13 -04002175 dev->restore(fMCRec->fMatrix);
Mike Reedd5674082019-04-19 15:00:47 -04002176 }
2177
2178 LOOPER_END
2179}
2180
reed41af9662015-01-05 07:49:08 -08002181void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002182 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002183 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002184 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002185 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002186 return;
2187 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002188 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002189
Ben Wagner2c312c42018-06-27 14:46:46 -04002190 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002191
2192 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002193 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002194 }
2195
2196 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002197}
2198
bsalomonac3aa242016-08-19 11:25:19 -07002199void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2200 SkScalar sweepAngle, bool useCenter,
2201 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002202 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002203 if (paint.canComputeFastBounds()) {
2204 SkRect storage;
2205 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002206 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002207 return;
2208 }
bsalomonac3aa242016-08-19 11:25:19 -07002209 }
2210
Ben Wagner2c312c42018-06-27 14:46:46 -04002211 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002212
2213 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002214 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002215 }
2216
2217 LOOPER_END
2218}
2219
reed41af9662015-01-05 07:49:08 -08002220void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002221 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002222 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002223 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2224 return;
2225 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002226 }
2227
2228 if (rrect.isRect()) {
2229 // call the non-virtual version
2230 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002231 return;
2232 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002233 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002234 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2235 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002236 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002237
Ben Wagner2c312c42018-06-27 14:46:46 -04002238 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002239
2240 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002241 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002242 }
2243
2244 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002245}
2246
Mike Reed822128b2017-02-28 16:41:03 -05002247void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002248 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002249 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002250 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2251 return;
2252 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002253 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002254
Ben Wagner2c312c42018-06-27 14:46:46 -04002255 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002256
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002257 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002258 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002259 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002260
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002261 LOOPER_END
2262}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002263
reed41af9662015-01-05 07:49:08 -08002264void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002265 if (!path.isFinite()) {
2266 return;
2267 }
2268
Mike Reed822128b2017-02-28 16:41:03 -05002269 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002270 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002271 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002272 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2273 return;
2274 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002275 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002276
Mike Reed822128b2017-02-28 16:41:03 -05002277 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002278 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002279 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002280 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002281 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002282 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002283
Ben Wagner2c312c42018-06-27 14:46:46 -04002284 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002285
2286 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002287 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002288 }
2289
reed@google.com4e2b3d32011-04-07 14:18:59 +00002290 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002291}
2292
reed262a71b2015-12-05 13:07:27 -08002293bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002294 if (!paint.getImageFilter()) {
2295 return false;
2296 }
2297
2298 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002299 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002300 return false;
2301 }
2302
2303 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2304 // Once we can filter and the filter will return a result larger than itself, we should be
2305 // able to remove this constraint.
2306 // skbug.com/4526
2307 //
2308 SkPoint pt;
2309 ctm.mapXY(x, y, &pt);
2310 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2311 return ir.contains(fMCRec->fRasterClip.getBounds());
2312}
2313
Mike Reedf441cfc2018-04-11 14:50:16 -04002314// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2315// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2316// null.
2317static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2318 if (paintParam) {
2319 *real = *paintParam;
2320 real->setStyle(SkPaint::kFill_Style);
2321 real->setPathEffect(nullptr);
2322 paintParam = real;
2323 }
2324 return paintParam;
2325}
2326
reeda85d4d02015-05-06 12:56:48 -07002327void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002328 SkPaint realPaint;
2329 paint = init_image_paint(&realPaint, paint);
2330
reeda85d4d02015-05-06 12:56:48 -07002331 SkRect bounds = SkRect::MakeXYWH(x, y,
2332 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002333 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002334 SkRect tmp = bounds;
2335 if (paint) {
2336 paint->computeFastBounds(tmp, &tmp);
2337 }
2338 if (this->quickReject(tmp)) {
2339 return;
2340 }
reeda85d4d02015-05-06 12:56:48 -07002341 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002342 // At this point we need a real paint object. If the caller passed null, then we should
2343 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2344 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2345 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002346
reeda2217ef2016-07-20 06:04:34 -07002347 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002348 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2349 *paint);
2350 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002351 special = this->getDevice()->makeSpecial(image);
2352 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002353 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002354 }
2355 }
2356
reed262a71b2015-12-05 13:07:27 -08002357 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2358
reeda85d4d02015-05-06 12:56:48 -07002359 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002360 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002361 if (special) {
2362 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002363 iter.fDevice->ctm().mapXY(x, y, &pt);
2364 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002365 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002366 SkScalarRoundToInt(pt.fY), pnt,
2367 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002368 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002369 iter.fDevice->drawImageRect(
2370 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2371 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002372 }
reeda85d4d02015-05-06 12:56:48 -07002373 }
halcanary9d524f22016-03-29 09:03:52 -07002374
reeda85d4d02015-05-06 12:56:48 -07002375 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002376}
2377
reed41af9662015-01-05 07:49:08 -08002378void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002379 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002380 SkPaint realPaint;
2381 paint = init_image_paint(&realPaint, paint);
2382
halcanary96fcdcc2015-08-27 07:41:13 -07002383 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002384 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002385 if (paint) {
2386 paint->computeFastBounds(dst, &storage);
2387 }
2388 if (this->quickReject(storage)) {
2389 return;
2390 }
reeda85d4d02015-05-06 12:56:48 -07002391 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002392 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002393
Ben Wagner2c312c42018-06-27 14:46:46 -04002394 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002395
reeda85d4d02015-05-06 12:56:48 -07002396 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002397 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002398 }
halcanary9d524f22016-03-29 09:03:52 -07002399
reeda85d4d02015-05-06 12:56:48 -07002400 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002401}
2402
reed41af9662015-01-05 07:49:08 -08002403void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002404 SkDEBUGCODE(bitmap.validate();)
2405
reed33366972015-10-08 09:22:02 -07002406 if (bitmap.drawsNothing()) {
2407 return;
2408 }
2409
Mike Reedf441cfc2018-04-11 14:50:16 -04002410 SkPaint realPaint;
2411 init_image_paint(&realPaint, paint);
2412 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002413
Mike Reed822128b2017-02-28 16:41:03 -05002414 SkRect bounds;
2415 bitmap.getBounds(&bounds);
2416 bounds.offset(x, y);
2417 bool canFastBounds = paint->canComputeFastBounds();
2418 if (canFastBounds) {
2419 SkRect storage;
2420 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002421 return;
2422 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002423 }
reed@google.com4b226022011-01-11 18:32:13 +00002424
reeda2217ef2016-07-20 06:04:34 -07002425 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002426 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2427 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002428 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002429 special = this->getDevice()->makeSpecial(bitmap);
2430 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002431 drawAsSprite = false;
2432 }
2433 }
2434
Mike Reed822128b2017-02-28 16:41:03 -05002435 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002436
2437 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002438 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002439 if (special) {
reed262a71b2015-12-05 13:07:27 -08002440 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002441 iter.fDevice->ctm().mapXY(x, y, &pt);
2442 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002443 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002444 SkScalarRoundToInt(pt.fY), pnt,
2445 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002446 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002447 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2448 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2449 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002450 }
reed33366972015-10-08 09:22:02 -07002451 }
msarettfbfa2582016-08-12 08:29:08 -07002452
reed33366972015-10-08 09:22:02 -07002453 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002454}
2455
reed@google.com9987ec32011-09-07 11:57:52 +00002456// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002457void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002458 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002459 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002460 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002461 return;
2462 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002463
halcanary96fcdcc2015-08-27 07:41:13 -07002464 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002465 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002466 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2467 return;
2468 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002469 }
reed@google.com3d608122011-11-21 15:16:16 +00002470
reed@google.com33535f32012-09-25 15:37:50 +00002471 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002472 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002473 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002475
Ben Wagner2c312c42018-06-27 14:46:46 -04002476 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002477
reed@google.com33535f32012-09-25 15:37:50 +00002478 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002479 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002480 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002481
reed@google.com33535f32012-09-25 15:37:50 +00002482 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002483}
2484
reed41af9662015-01-05 07:49:08 -08002485void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002486 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002487 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002488 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002489}
2490
reed4c21dc52015-06-25 12:32:03 -07002491void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2492 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002493 SkPaint realPaint;
2494 paint = init_image_paint(&realPaint, paint);
2495
halcanary96fcdcc2015-08-27 07:41:13 -07002496 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002497 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002498 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2499 return;
2500 }
reed@google.com3d608122011-11-21 15:16:16 +00002501 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002502 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002503
Ben Wagner2c312c42018-06-27 14:46:46 -04002504 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002505
reed4c21dc52015-06-25 12:32:03 -07002506 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002507 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002508 }
halcanary9d524f22016-03-29 09:03:52 -07002509
reed4c21dc52015-06-25 12:32:03 -07002510 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002511}
2512
reed41af9662015-01-05 07:49:08 -08002513void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2514 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002515 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002516 SkPaint realPaint;
2517 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002518
halcanary96fcdcc2015-08-27 07:41:13 -07002519 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002520 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002521 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2522 return;
2523 }
reed4c21dc52015-06-25 12:32:03 -07002524 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002525 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002526
Ben Wagner2c312c42018-06-27 14:46:46 -04002527 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002528
reed4c21dc52015-06-25 12:32:03 -07002529 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002530 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002531 }
halcanary9d524f22016-03-29 09:03:52 -07002532
reed4c21dc52015-06-25 12:32:03 -07002533 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002534}
2535
msarett16882062016-08-16 09:31:08 -07002536void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2537 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002538 SkPaint realPaint;
2539 paint = init_image_paint(&realPaint, paint);
2540
msarett16882062016-08-16 09:31:08 -07002541 if (nullptr == paint || paint->canComputeFastBounds()) {
2542 SkRect storage;
2543 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2544 return;
2545 }
2546 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002547 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002548
Ben Wagner2c312c42018-06-27 14:46:46 -04002549 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002550
2551 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002552 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002553 }
2554
2555 LOOPER_END
2556}
2557
2558void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2559 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002560 SkPaint realPaint;
2561 paint = init_image_paint(&realPaint, paint);
2562
msarett16882062016-08-16 09:31:08 -07002563 if (nullptr == paint || paint->canComputeFastBounds()) {
2564 SkRect storage;
2565 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2566 return;
2567 }
2568 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002569 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002570
Ben Wagner2c312c42018-06-27 14:46:46 -04002571 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002572
2573 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002574 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002575 }
2576
2577 LOOPER_END
2578}
2579
fmalita00d5c2c2014-08-21 08:53:26 -07002580void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2581 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002582 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002583 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002584 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002585 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002586 SkRect tmp;
2587 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2588 return;
2589 }
2590 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002591 }
2592
fmalita024f9962015-03-03 19:08:17 -08002593 // We cannot filter in the looper as we normally do, because the paint is
2594 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002595 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002596
fmalitaaa1b9122014-08-28 14:32:24 -07002597 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002598 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002599 }
2600
fmalitaaa1b9122014-08-28 14:32:24 -07002601 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002602}
2603
Mike Reed358fcad2018-11-23 15:27:51 -05002604// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002605void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002606 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2607 TRACE_EVENT0("skia", TRACE_FUNC);
2608 if (byteLength) {
2609 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002610 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002611 }
2612}
Mike Reed4f81bb72019-01-23 09:23:00 -05002613
fmalita00d5c2c2014-08-21 08:53:26 -07002614void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2615 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002616 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002617 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002618 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002619 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002620}
reed@google.come0d9ce82014-04-23 04:00:17 +00002621
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002622void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002623 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002624 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002625
2626 while (iter.next()) {
2627 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002628 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002629 }
2630
2631 LOOPER_END
2632}
2633
dandovb3c9d1c2014-08-12 08:34:29 -07002634void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002635 const SkPoint texCoords[4], SkBlendMode bmode,
2636 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002637 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002638 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002639 return;
2640 }
mtklein6cfa73a2014-08-13 13:33:49 -07002641
Mike Reedfaba3712016-11-03 14:45:31 -04002642 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002643}
2644
2645void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002646 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002647 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002648 // Since a patch is always within the convex hull of the control points, we discard it when its
2649 // bounding rectangle is completely outside the current clip.
2650 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002651 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002652 if (this->quickReject(bounds)) {
2653 return;
2654 }
mtklein6cfa73a2014-08-13 13:33:49 -07002655
Ben Wagner2c312c42018-06-27 14:46:46 -04002656 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002657
dandovecfff212014-08-04 10:02:00 -07002658 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002659 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002660 }
mtklein6cfa73a2014-08-13 13:33:49 -07002661
dandovecfff212014-08-04 10:02:00 -07002662 LOOPER_END
2663}
2664
reeda8db7282015-07-07 10:22:31 -07002665void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002666#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002667 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002668#endif
reede3b38ce2016-01-08 09:18:44 -08002669 RETURN_ON_NULL(dr);
2670 if (x || y) {
2671 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2672 this->onDrawDrawable(dr, &matrix);
2673 } else {
2674 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002675 }
2676}
2677
reeda8db7282015-07-07 10:22:31 -07002678void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002679#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002680 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002681#endif
reede3b38ce2016-01-08 09:18:44 -08002682 RETURN_ON_NULL(dr);
2683 if (matrix && matrix->isIdentity()) {
2684 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002685 }
reede3b38ce2016-01-08 09:18:44 -08002686 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002687}
2688
2689void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002690 // drawable bounds are no longer reliable (e.g. android displaylist)
2691 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002692 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002693}
2694
reed71c3c762015-06-24 10:29:17 -07002695void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002696 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002697 const SkRect* cull, const SkPaint* paint) {
2698 if (cull && this->quickReject(*cull)) {
2699 return;
2700 }
2701
2702 SkPaint pnt;
2703 if (paint) {
2704 pnt = *paint;
2705 }
halcanary9d524f22016-03-29 09:03:52 -07002706
Ben Wagner2c312c42018-06-27 14:46:46 -04002707 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002708 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002709 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002710 }
2711 LOOPER_END
2712}
2713
reedf70b5312016-03-04 16:36:20 -08002714void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2715 SkASSERT(key);
2716
2717 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002718 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002719 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002720 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002721 }
2722 LOOPER_END
2723}
2724
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002725void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2726 SkColor color, SkBlendMode mode) {
2727 SkASSERT(r.isSorted());
2728
2729 // If this used a paint, it would be a filled color with blend mode, which does not
2730 // need to use an autodraw loop, so use SkDrawIter directly.
2731 if (this->quickReject(r)) {
2732 return;
2733 }
2734
2735 this->predrawNotify();
2736 SkDrawIter iter(this);
2737 while(iter.next()) {
2738 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2739 }
2740}
2741
2742void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2743 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2744 const SkPaint* paint, SrcRectConstraint constraint) {
2745 SkPaint realPaint;
2746 init_image_paint(&realPaint, paint);
2747
2748 // Looper is used when there are image filters, which drawEdgeAAImageSet needs to support
2749 // for Chromium's RenderPassDrawQuads' filters.
2750 LOOPER_BEGIN(realPaint, nullptr)
2751 while (iter.next()) {
2752 iter.fDevice->drawEdgeAAImageSet(
2753 imageSet, count, dstClips, preViewMatrices, looper.paint(), constraint);
2754 }
2755 LOOPER_END
2756}
2757
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758//////////////////////////////////////////////////////////////////////////////
2759// These methods are NOT virtual, and therefore must call back into virtual
2760// methods, rather than actually drawing themselves.
2761//////////////////////////////////////////////////////////////////////////////
2762
reed374772b2016-10-05 17:33:02 -07002763void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002765 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002766 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767 this->drawPaint(paint);
2768}
2769
2770void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002771 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2773}
2774
Mike Reed3661bc92017-02-22 13:21:42 -05002775void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777 pts[0].set(x0, y0);
2778 pts[1].set(x1, y1);
2779 this->drawPoints(kLines_PointMode, 2, pts, paint);
2780}
2781
Mike Reed3661bc92017-02-22 13:21:42 -05002782void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783 if (radius < 0) {
2784 radius = 0;
2785 }
2786
2787 SkRect r;
2788 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002789 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790}
2791
2792void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2793 const SkPaint& paint) {
2794 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002795 SkRRect rrect;
2796 rrect.setRectXY(r, rx, ry);
2797 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798 } else {
2799 this->drawRect(r, paint);
2800 }
2801}
2802
reed@android.com8a1c16f2008-12-17 15:59:43 +00002803void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2804 SkScalar sweepAngle, bool useCenter,
2805 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002806 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002807 if (oval.isEmpty() || !sweepAngle) {
2808 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809 }
bsalomon21af9ca2016-08-25 12:29:23 -07002810 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002811}
2812
reed@android.comf76bacf2009-05-13 14:00:33 +00002813///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002814#ifdef SK_DISABLE_SKPICTURE
2815void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002816
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002817
2818void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2819 const SkPaint* paint) {}
2820#else
Mike Klein88d90712018-01-27 17:30:04 +00002821/**
2822 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2823 * against the playback cost of recursing into the subpicture to get at its actual ops.
2824 *
2825 * For now we pick a conservatively small value, though measurement (and other heuristics like
2826 * the type of ops contained) may justify changing this value.
2827 */
2828#define kMaxPictureOpsToUnrollInsteadOfRef 1
2829
reedd5fa1a42014-08-09 11:08:05 -07002830void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002831 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002832 RETURN_ON_NULL(picture);
2833
reede3b38ce2016-01-08 09:18:44 -08002834 if (matrix && matrix->isIdentity()) {
2835 matrix = nullptr;
2836 }
Mike Klein88d90712018-01-27 17:30:04 +00002837 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2838 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2839 picture->playback(this);
2840 } else {
2841 this->onDrawPicture(picture, matrix, paint);
2842 }
reedd5fa1a42014-08-09 11:08:05 -07002843}
robertphillips9b14f262014-06-04 05:40:44 -07002844
reedd5fa1a42014-08-09 11:08:05 -07002845void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2846 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002847 if (!paint || paint->canComputeFastBounds()) {
2848 SkRect bounds = picture->cullRect();
2849 if (paint) {
2850 paint->computeFastBounds(bounds, &bounds);
2851 }
2852 if (matrix) {
2853 matrix->mapRect(&bounds);
2854 }
2855 if (this->quickReject(bounds)) {
2856 return;
2857 }
2858 }
2859
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002860 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002861 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002862}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002863#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002864
reed@android.com8a1c16f2008-12-17 15:59:43 +00002865///////////////////////////////////////////////////////////////////////////////
2866///////////////////////////////////////////////////////////////////////////////
2867
reed3aafe112016-08-18 12:45:34 -07002868SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002869 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002870
2871 SkASSERT(canvas);
2872
reed3aafe112016-08-18 12:45:34 -07002873 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002874 fDone = !fImpl->next();
2875}
2876
2877SkCanvas::LayerIter::~LayerIter() {
2878 fImpl->~SkDrawIter();
2879}
2880
2881void SkCanvas::LayerIter::next() {
2882 fDone = !fImpl->next();
2883}
2884
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002885SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002886 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002887}
2888
2889const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002890 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002891}
2892
2893const SkPaint& SkCanvas::LayerIter::paint() const {
2894 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002895 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002896 paint = &fDefaultPaint;
2897 }
2898 return *paint;
2899}
2900
Mike Reedca37f322018-03-08 13:22:16 -05002901SkIRect SkCanvas::LayerIter::clipBounds() const {
2902 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002903}
2904
reed@android.com8a1c16f2008-12-17 15:59:43 +00002905int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2906int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002907
2908///////////////////////////////////////////////////////////////////////////////
2909
Brian Osmane8a98632019-04-10 10:26:10 -04002910SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2911SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2912SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2913SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2914
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002915SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2916 const SkRect& dstRect, int matrixIndex, float alpha,
2917 unsigned aaFlags, bool hasClip)
2918 : fImage(std::move(image))
2919 , fSrcRect(srcRect)
2920 , fDstRect(dstRect)
2921 , fMatrixIndex(matrixIndex)
2922 , fAlpha(alpha)
2923 , fAAFlags(aaFlags)
2924 , fHasClip(hasClip) {}
2925
2926SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2927 const SkRect& dstRect, float alpha, unsigned aaFlags)
2928 : fImage(std::move(image))
2929 , fSrcRect(srcRect)
2930 , fDstRect(dstRect)
2931 , fAlpha(alpha)
2932 , fAAFlags(aaFlags) {}
2933
2934///////////////////////////////////////////////////////////////////////////////
2935
Mike Reed5df49342016-11-12 08:06:55 -06002936std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002937 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002938 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002939 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002940 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002941
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002942 SkBitmap bitmap;
2943 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002944 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002945 }
Mike Reed12f77342017-11-08 11:19:52 -05002946
2947 return props ?
2948 skstd::make_unique<SkCanvas>(bitmap, *props) :
2949 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002950}
reedd5fa1a42014-08-09 11:08:05 -07002951
2952///////////////////////////////////////////////////////////////////////////////
2953
Florin Malitaee424ac2016-12-01 12:47:59 -05002954SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002955 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002956
Florin Malita439ace92016-12-02 12:05:41 -05002957SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002958 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002959
Herb Derbyefe39bc2018-05-01 17:06:20 -04002960SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002961 : INHERITED(device) {}
2962
Florin Malitaee424ac2016-12-01 12:47:59 -05002963SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2964 (void)this->INHERITED::getSaveLayerStrategy(rec);
2965 return kNoLayer_SaveLayerStrategy;
2966}
2967
Mike Reed148b7fd2018-12-18 17:38:18 -05002968bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2969 return false;
2970}
2971
Florin Malitaee424ac2016-12-01 12:47:59 -05002972///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002973
reed73603f32016-09-20 08:42:38 -07002974static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2975static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2976static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2977static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2978static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2979static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002980
2981///////////////////////////////////////////////////////////////////////////////////////////////////
2982
2983SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2984 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002985 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002986 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2987 SkIPoint origin = dev->getOrigin();
2988 SkMatrix ctm = this->getTotalMatrix();
2989 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2990
2991 SkIRect clip = fMCRec->fRasterClip.getBounds();
2992 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002993 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002994 clip.setEmpty();
2995 }
2996
2997 fAllocator->updateHandle(handle, ctm, clip);
2998 return handle;
2999 }
3000 return nullptr;
3001}
3002
3003static bool install(SkBitmap* bm, const SkImageInfo& info,
3004 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04003005 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05003006}
3007
3008SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3009 SkBitmap* bm) {
3010 SkRasterHandleAllocator::Rec rec;
3011 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3012 return nullptr;
3013 }
3014 return rec.fHandle;
3015}
3016
3017std::unique_ptr<SkCanvas>
3018SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3019 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04003020 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05003021 return nullptr;
3022 }
3023
3024 SkBitmap bm;
3025 Handle hndl;
3026
3027 if (rec) {
3028 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3029 } else {
3030 hndl = alloc->allocBitmap(info, &bm);
3031 }
3032 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3033}
Mike Reed7c9c9e42018-01-03 09:23:34 -05003034
3035///////////////////////////////////////////////////////////////////////////////////////////////////
3036
3037