blob: 3951f85cd361fef3fe3eee5b3ebf6e5e13304fa6 [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 Ludwig8ee6cf32019-08-02 09:57:04 -040031#include "src/core/SkImageFilter_Base.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 -0700313/**
314 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700315 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700316 */
reedd053ce92016-03-22 10:17:23 -0700317static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700318 SkImageFilter* imgf = paint.getImageFilter();
319 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700320 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700321 }
322
reedd053ce92016-03-22 10:17:23 -0700323 SkColorFilter* imgCFPtr;
324 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700325 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700326 }
reedd053ce92016-03-22 10:17:23 -0700327 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700328
329 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700330 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700331 // there is no existing paint colorfilter, so we can just return the imagefilter's
332 return imgCF;
333 }
334
335 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
336 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500337 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700338}
339
senorblanco87e066e2015-10-28 11:23:36 -0700340/**
341 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
342 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
343 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
344 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
345 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
346 * conservative "effective" bounds based on the settings in the paint... with one exception. This
347 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
348 * deliberately ignored.
349 */
350static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
351 const SkRect& rawBounds,
352 SkRect* storage) {
353 SkPaint tmpUnfiltered(paint);
354 tmpUnfiltered.setImageFilter(nullptr);
355 if (tmpUnfiltered.canComputeFastBounds()) {
356 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
357 } else {
358 return rawBounds;
359 }
360}
361
Mike Reed38992392019-07-30 10:48:15 -0400362class AutoLayerForImageFilter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363public:
senorblanco87e066e2015-10-28 11:23:36 -0700364 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
365 // paint. It's used to determine the size of the offscreen layer for filters.
366 // If null, the clip will be used instead.
Mike Reed38992392019-07-30 10:48:15 -0400367 AutoLayerForImageFilter(SkCanvas* canvas, const SkPaint& origPaint,
368 bool skipLayerForImageFilter = false,
369 const SkRect* rawBounds = nullptr) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000370 fCanvas = canvas;
Mike Reed38992392019-07-30 10:48:15 -0400371 fPaint = &origPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000372 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700373 fTempLayerForImageFilter = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374
Mike Reed38992392019-07-30 10:48:15 -0400375 if (auto simplifiedCF = image_to_color_filter(origPaint)) {
376 SkASSERT(!fLazyPaint.isValid());
377 SkPaint* paint = fLazyPaint.set(origPaint);
reedd053ce92016-03-22 10:17:23 -0700378 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700379 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700380 fPaint = paint;
381 }
382
383 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700384 /**
385 * We implement ImageFilters for a given draw by creating a layer, then applying the
386 * imagefilter to the pixels of that layer (its backing surface/image), and then
387 * we call restore() to xfer that layer to the main canvas.
388 *
389 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
390 * 2. Generate the src pixels:
391 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
392 * return (fPaint). We then draw the primitive (using srcover) into a cleared
393 * buffer/surface.
394 * 3. Restore the layer created in #1
395 * The imagefilter is passed the buffer/surface from the layer (now filled with the
396 * src pixels of the primitive). It returns a new "filtered" buffer, which we
397 * draw onto the previous layer using the xfermode from the original paint.
398 */
Mike Reed38992392019-07-30 10:48:15 -0400399
400 SkPaint restorePaint;
401 restorePaint.setImageFilter(fPaint->refImageFilter());
402 restorePaint.setBlendMode(fPaint->getBlendMode());
403
senorblanco87e066e2015-10-28 11:23:36 -0700404 SkRect storage;
405 if (rawBounds) {
406 // Make rawBounds include all paint outsets except for those due to image filters.
407 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
408 }
Mike Reed38992392019-07-30 10:48:15 -0400409 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &restorePaint),
reed76033be2015-03-14 10:54:31 -0700410 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700411 fTempLayerForImageFilter = true;
reed@google.com8926b162012-03-23 15:36:36 +0000412
Mike Reed38992392019-07-30 10:48:15 -0400413 // Remove the restorePaint fields from our "working" paint
414 SkASSERT(!fLazyPaint.isValid());
415 SkPaint* paint = fLazyPaint.set(origPaint);
416 paint->setImageFilter(nullptr);
417 paint->setBlendMode(SkBlendMode::kSrcOver);
418 fPaint = paint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000419 }
420 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000421
Mike Reed38992392019-07-30 10:48:15 -0400422 ~AutoLayerForImageFilter() {
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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434private:
Mike Reed38992392019-07-30 10:48:15 -0400435 SkLazyPaint fLazyPaint; // base paint storage in case we need to modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000436 SkCanvas* fCanvas;
Mike Reed38992392019-07-30 10:48:15 -0400437 const SkPaint* fPaint; // points to either the original paint, or lazy (if we needed it)
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000438 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700439 bool fTempLayerForImageFilter;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440};
441
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442////////// macros to place around the internal draw calls //////////////////
443
Mike Reed38992392019-07-30 10:48:15 -0400444#define DRAW_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
reed3aafe112016-08-18 12:45:34 -0700445 this->predrawNotify(); \
Mike Reed38992392019-07-30 10:48:15 -0400446 AutoLayerForImageFilter draw(this, paint, skipLayerForFilter, bounds); \
447 { SkDrawIter iter(this);
reed262a71b2015-12-05 13:07:27 -0800448
449
Mike Reed38992392019-07-30 10:48:15 -0400450#define DRAW_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000451 this->predrawNotify(); \
Mike Reed38992392019-07-30 10:48:15 -0400452 AutoLayerForImageFilter draw(this, paint, true); \
453 { SkDrawIter iter(this);
reed@google.com8926b162012-03-23 15:36:36 +0000454
Mike Reed38992392019-07-30 10:48:15 -0400455#define DRAW_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000456 this->predrawNotify(); \
Mike Reed38992392019-07-30 10:48:15 -0400457 AutoLayerForImageFilter draw(this, paint, false, bounds); \
458 { SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000459
Mike Reed38992392019-07-30 10:48:15 -0400460#define DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700461 this->predrawNotify(bounds, &paint, auxOpaque); \
Mike Reed38992392019-07-30 10:48:15 -0400462 AutoLayerForImageFilter draw(this, paint, false, bounds); \
463 { SkDrawIter iter(this);
reedc83a2972015-07-16 07:40:45 -0700464
Mike Reed38992392019-07-30 10:48:15 -0400465#define DRAW_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466
467////////////////////////////////////////////////////////////////////////////
468
msarettfbfa2582016-08-12 08:29:08 -0700469static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
470 if (bounds.isEmpty()) {
471 return SkRect::MakeEmpty();
472 }
473
474 // Expand bounds out by 1 in case we are anti-aliasing. We store the
475 // bounds as floats to enable a faster quick reject implementation.
476 SkRect dst;
477 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
478 return dst;
479}
480
mtkleinfeaadee2015-04-08 11:25:48 -0700481void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
482 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700483 fMCRec->reset(bounds);
484
485 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500486 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400487 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700488 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700489 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700490}
491
Hal Canary363a3f82018-10-04 11:04:48 -0400492void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000493 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800494 fSaveCount = 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495
496 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500497 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500498 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700499 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000500
reeda499f902015-05-01 09:34:31 -0700501 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
502 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400503 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700504
reed@android.com8a1c16f2008-12-17 15:59:43 +0000505 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506
halcanary96fcdcc2015-08-27 07:41:13 -0700507 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000508
reedf92c8662014-08-18 08:02:43 -0700509 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700510 // The root device and the canvas should always have the same pixel geometry
511 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800512 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700513 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500514
Mike Reedc42a1cd2017-02-14 14:25:14 -0500515 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700516 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400517
Herb Derby59d997a2018-06-07 12:44:09 -0400518 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519}
520
reed@google.comcde92112011-07-06 20:00:52 +0000521SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000522 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700523 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000524{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000525 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000526
Hal Canary363a3f82018-10-04 11:04:48 -0400527 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000528}
529
reed96a857e2015-01-25 10:33:58 -0800530SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000531 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800532 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000533{
534 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400535 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400536 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700537}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000538
Hal Canary363a3f82018-10-04 11:04:48 -0400539SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700540 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700541 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700542{
543 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700544
Mike Reed566e53c2017-03-10 10:49:45 -0500545 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400546 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700547}
548
Herb Derbyefe39bc2018-05-01 17:06:20 -0400549SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000550 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700551 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000552{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700554
Hal Canary363a3f82018-10-04 11:04:48 -0400555 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700556}
557
reed4a8126e2014-09-22 07:29:03 -0700558SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700559 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700560 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700561{
562 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700563
Mike Reed910ca0f2018-04-25 13:04:05 -0400564 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400565 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700566}
reed29c857d2014-09-21 10:25:07 -0700567
Mike Reed356f7c22017-01-10 11:58:39 -0500568SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
569 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700570 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
571 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500572 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700573{
574 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700575
Mike Reed910ca0f2018-04-25 13:04:05 -0400576 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400577 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578}
579
Mike Reed356f7c22017-01-10 11:58:39 -0500580SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
581
Matt Sarett31f99ce2017-04-11 08:46:01 -0400582#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
583SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
584 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
585 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
586 , fAllocator(nullptr)
587{
588 inc_canvas();
589
590 SkBitmap tmp(bitmap);
591 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400592 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400593 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400594}
595#endif
596
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597SkCanvas::~SkCanvas() {
598 // free up the contents of our deque
599 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000600
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601 this->internalRestore(); // restore the last, since we're going away
602
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603 dec_canvas();
604}
605
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606///////////////////////////////////////////////////////////////////////////////
607
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000608void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700609 this->onFlush();
610}
611
612void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000613 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000614 if (device) {
615 device->flush();
616 }
617}
618
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000619SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000620 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000621 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
622}
623
senorblancoafc7cce2016-02-02 18:44:15 -0800624SkIRect SkCanvas::getTopLayerBounds() const {
625 SkBaseDevice* d = this->getTopDevice();
626 if (!d) {
627 return SkIRect::MakeEmpty();
628 }
629 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
630}
631
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000632SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000634 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000635 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400636 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637}
638
Florin Malita0ed3b642017-01-13 16:56:38 +0000639SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400640 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000641}
642
Mike Reed353196f2017-07-21 11:01:18 -0400643bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000644 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400645 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000646}
647
Mike Reed353196f2017-07-21 11:01:18 -0400648bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
649 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400650}
651
652bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
653 SkPixmap pm;
654 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
655}
656
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000657bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400658 SkPixmap pm;
659 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700660 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000661 }
662 return false;
663}
664
Matt Sarett03dd6d52017-01-23 12:15:09 -0500665bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000666 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000667 SkBaseDevice* device = this->getDevice();
668 if (!device) {
669 return false;
670 }
671
Matt Sarett03dd6d52017-01-23 12:15:09 -0500672 // This check gives us an early out and prevents generation ID churn on the surface.
673 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
674 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
Mike Reed92b33352019-08-24 19:39:13 -0400675 if (!srcRect.intersect({0, 0, device->width(), device->height()})) {
Matt Sarett03dd6d52017-01-23 12:15:09 -0500676 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000677 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000678
Matt Sarett03dd6d52017-01-23 12:15:09 -0500679 // Tell our owning surface to bump its generation ID.
680 const bool completeOverwrite =
681 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700682 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700683
Matt Sarett03dd6d52017-01-23 12:15:09 -0500684 // This can still fail, most notably in the case of a invalid color type or alpha type
685 // conversion. We could pull those checks into this function and avoid the unnecessary
686 // generation ID bump. But then we would be performing those checks twice, since they
687 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400688 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000689}
reed@google.com51df9e32010-12-23 19:29:18 +0000690
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691//////////////////////////////////////////////////////////////////////////////
692
reed2ff1fce2014-12-11 07:07:37 -0800693void SkCanvas::checkForDeferredSave() {
694 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800695 this->doSave();
696 }
697}
698
reedf0090cb2014-11-26 08:55:51 -0800699int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800700#ifdef SK_DEBUG
701 int count = 0;
702 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
703 for (;;) {
704 const MCRec* rec = (const MCRec*)iter.next();
705 if (!rec) {
706 break;
707 }
708 count += 1 + rec->fDeferredSaveCount;
709 }
710 SkASSERT(count == fSaveCount);
711#endif
712 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800713}
714
715int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800716 fSaveCount += 1;
717 fMCRec->fDeferredSaveCount += 1;
718 return this->getSaveCount() - 1; // return our prev value
719}
720
721void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800722 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700723
724 SkASSERT(fMCRec->fDeferredSaveCount > 0);
725 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800726 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800727}
728
729void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800730 if (fMCRec->fDeferredSaveCount > 0) {
731 SkASSERT(fSaveCount > 1);
732 fSaveCount -= 1;
733 fMCRec->fDeferredSaveCount -= 1;
734 } else {
735 // check for underflow
736 if (fMCStack.count() > 1) {
737 this->willRestore();
738 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700739 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800740 this->internalRestore();
741 this->didRestore();
742 }
reedf0090cb2014-11-26 08:55:51 -0800743 }
744}
745
746void SkCanvas::restoreToCount(int count) {
747 // sanity check
748 if (count < 1) {
749 count = 1;
750 }
mtkleinf0f14112014-12-12 08:46:25 -0800751
reedf0090cb2014-11-26 08:55:51 -0800752 int n = this->getSaveCount() - count;
753 for (int i = 0; i < n; ++i) {
754 this->restore();
755 }
756}
757
reed2ff1fce2014-12-11 07:07:37 -0800758void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000759 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700760 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000762
Mike Reedc42a1cd2017-02-14 14:25:14 -0500763 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764}
765
reed4960eee2015-12-18 07:09:18 -0800766bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400767 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768}
769
reed4960eee2015-12-18 07:09:18 -0800770bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700771 SkIRect* intersection, const SkImageFilter* imageFilter) {
Michael Ludwigaa861a12019-07-19 10:13:47 -0400772 // clipRectBounds() is called to determine the input layer size needed for a given image filter.
773 // The coordinate space of the rectangle passed to filterBounds(kReverse) is meant to be in the
774 // filtering layer space. Here, 'clipBounds' is always in the true device space. When an image
775 // filter does not require a decomposed CTM matrix, the filter space and device space are the
776 // same. When it has been decomposed, we want the original image filter node to process the
777 // bounds in the layer space represented by the decomposed scale matrix. 'imageFilter' is no
778 // longer the original filter, but has the remainder matrix baked into it, and passing in the
779 // the true device clip bounds ensures that the matrix image filter provides a layer clip bounds
780 // to the original filter node (barring inflation from consecutive calls to mapRect). While
781 // initially counter-intuitive given the apparent inconsistency of coordinate spaces, always
782 // passing getDeviceClipBounds() to 'imageFilter' is correct.
783 // FIXME (michaelludwig) - When the remainder matrix is instead applied as a final draw, it will
784 // be important to more accurately calculate the clip bounds in the layer space for the original
785 // image filter (similar to how matrix image filter does it, but ideally without the inflation).
Mike Reed918e1442017-01-23 11:39:45 -0500786 SkIRect clipBounds = this->getDeviceClipBounds();
787 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000788 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000789 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000790
reed96e657d2015-03-10 17:30:07 -0700791 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
792
Robert Phillips12078432018-05-17 11:17:39 -0400793 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
794 // If the image filter DAG affects transparent black then we will need to render
795 // out to the clip bounds
796 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000797 }
Robert Phillips12078432018-05-17 11:17:39 -0400798
799 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700800 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700802 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400803 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400805 inputSaveLayerBounds = clipBounds;
806 }
807
808 if (imageFilter) {
809 // expand the clip bounds by the image filter DAG to include extra content that might
810 // be required by the image filters.
811 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
812 SkImageFilter::kReverse_MapDirection,
813 &inputSaveLayerBounds);
814 }
815
816 SkIRect clippedSaveLayerBounds;
817 if (bounds) {
818 // For better or for worse, user bounds currently act as a hard clip on the layer's
819 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
820 clippedSaveLayerBounds = inputSaveLayerBounds;
821 } else {
822 // If there are no user bounds, we don't want to artificially restrict the resulting
823 // layer bounds, so allow the expanded clip bounds free reign.
824 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800826
827 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400828 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800829 if (BoundsAffectsClip(saveLayerFlags)) {
830 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
831 fMCRec->fRasterClip.setEmpty();
832 fDeviceClipBounds.setEmpty();
833 }
834 return false;
835 }
Robert Phillips12078432018-05-17 11:17:39 -0400836 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000837
reed4960eee2015-12-18 07:09:18 -0800838 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700839 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400840 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
841 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000842 }
843
844 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400845 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000846 }
Robert Phillips12078432018-05-17 11:17:39 -0400847
junov@chromium.orga907ac32012-02-24 21:54:07 +0000848 return true;
849}
850
reed4960eee2015-12-18 07:09:18 -0800851int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
852 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000853}
854
Cary Clarke041e312018-03-06 13:00:52 -0500855int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700856 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400857 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
858 // no need for the layer (or any of the draws until the matching restore()
859 this->save();
860 this->clipRect({0,0,0,0});
861 } else {
862 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
863 fSaveCount += 1;
864 this->internalSaveLayer(rec, strategy);
865 }
reed4960eee2015-12-18 07:09:18 -0800866 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800867}
868
Mike Reed148b7fd2018-12-18 17:38:18 -0500869int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
870 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
871 // Assuming clips never expand, if the request bounds is outside of the current clip
872 // there is no need to copy/restore the area, so just devolve back to a regular save.
873 this->save();
874 } else {
875 bool doTheWork = this->onDoSaveBehind(bounds);
876 fSaveCount += 1;
877 this->internalSave();
878 if (doTheWork) {
879 this->internalSaveBehind(bounds);
880 }
881 }
882 return this->getSaveCount() - 1;
883}
884
reeda2217ef2016-07-20 06:04:34 -0700885void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500886 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500887 const SkMatrix& ctm) {
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400888 SkPaint p;
Michael Ludwig08b260c2019-05-17 11:21:53 -0400889 SkIRect snapBounds = SkIRect::MakeXYWH(dstOrigin.x() - src->getOrigin().x(),
890 dstOrigin.y() - src->getOrigin().y(),
891 dst->width(), dst->height());
892 int x = 0;
893 int y = 0;
894
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400895 if (filter) {
Michael Ludwig08b260c2019-05-17 11:21:53 -0400896 // Calculate expanded snap bounds
897 SkIRect newBounds = filter->filterBounds(
898 snapBounds, ctm, SkImageFilter::kReverse_MapDirection, &snapBounds);
899 // Must clamp to valid src since the filter or rotations may expand beyond what's readable
900 SkIRect srcR = SkIRect::MakeWH(src->width(), src->height());
901 if (!newBounds.intersect(srcR)) {
902 return;
903 }
904
905 x = newBounds.fLeft - snapBounds.fLeft;
906 y = newBounds.fTop - snapBounds.fTop;
907 snapBounds = newBounds;
908
909 SkMatrix localCTM;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400910 sk_sp<SkImageFilter> modifiedFilter = as_IFB(filter)->applyCTMForBackdrop(ctm, &localCTM);
Michael Ludwig08b260c2019-05-17 11:21:53 -0400911 // Account for the origin offset in the CTM
912 localCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
913
914 // In this case we always wrap the filter (even when it's the original) with 'localCTM'
915 // since there's no device CTM stack that provides it to the image filter context.
916 // FIXME skbug.com/9074 - once perspective is properly supported, drop the
917 // localCTM.hasPerspective condition from assert.
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400918 SkASSERT(localCTM.isScaleTranslate() || as_IFB(filter)->canHandleComplexCTM() ||
Michael Ludwig08b260c2019-05-17 11:21:53 -0400919 localCTM.hasPerspective());
920 p.setImageFilter(modifiedFilter->makeWithLocalMatrix(localCTM));
Michael Ludwig7d2ad0f2019-05-03 17:09:47 -0400921 }
922
Michael Ludwigac352122019-08-28 21:03:05 +0000923 auto special = src->snapSpecial(snapBounds);
reeda2217ef2016-07-20 06:04:34 -0700924 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400925 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700926 }
robertphillips7354a4b2015-12-16 05:08:27 -0800927}
reed70ee31b2015-12-10 13:44:45 -0800928
Mike Reed25394292019-03-07 09:36:36 -0500929// This is shared by all backends, but contains raster-specific thoughts. Can we defer to the
930// device to perform this?
Mike Kleine083f7c2018-02-07 12:54:27 -0500931static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500932 // Need to force L32 for now if we have an image filter.
Mike Reed25394292019-03-07 09:36:36 -0500933 // If filters ever support other colortypes, e.g. F16, we can modify this check.
Mike Klein649fb732018-02-26 15:09:16 -0500934 if (paint && paint->getImageFilter()) {
Mike Reed25394292019-03-07 09:36:36 -0500935 // TODO: can we query the imagefilter, to see if it can handle floats (so we don't always
936 // use N32 when the layer itself was float)?
937 return SkImageInfo::MakeN32Premul(w, h, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800938 }
Mike Klein649fb732018-02-26 15:09:16 -0500939
940 SkColorType ct = prev.colorType();
941 if (prev.bytesPerPixel() <= 4) {
942 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
943 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
944 ct = kN32_SkColorType;
945 }
946 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800947}
948
reed4960eee2015-12-18 07:09:18 -0800949void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700950 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800951 const SkRect* bounds = rec.fBounds;
952 const SkPaint* paint = rec.fPaint;
953 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
954
Mike Reed5532c2a2019-02-23 12:00:32 -0500955 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
956 // regardless of any hint-rect from the caller. skbug.com/8783
957 if (rec.fBackdrop) {
958 bounds = nullptr;
959 }
960
reed8c30a812016-04-20 16:36:51 -0700961 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400962 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700963 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400964 MCRec* modifiedRec = nullptr;
Michael Ludwig08b260c2019-05-17 11:21:53 -0400965
reed8c30a812016-04-20 16:36:51 -0700966 /*
Michael Ludwig08b260c2019-05-17 11:21:53 -0400967 * Many ImageFilters (so far) do not (on their own) correctly handle matrices (CTM) that
968 * contain rotation/skew/etc. We rely on applyCTM to create a new image filter DAG as needed to
969 * accommodate this, but it requires update the CTM we use when drawing into the layer.
reed8c30a812016-04-20 16:36:51 -0700970 *
971 * 1. Stash off the current CTM
Michael Ludwig08b260c2019-05-17 11:21:53 -0400972 * 2. Apply the CTM to imagefilter, which decomposes it into simple and complex transforms
973 * if necessary.
974 * 3. Wack the CTM to be the remaining scale matrix and use the modified imagefilter, which
975 * is a MatrixImageFilter that contains the complex matrix.
reed8c30a812016-04-20 16:36:51 -0700976 * 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 -0400977 * 5. During restore, the MatrixImageFilter automatically applies complex stage to the output
reed8c30a812016-04-20 16:36:51 -0700978 * of the original imagefilter, and draw that (via drawSprite)
979 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
980 *
981 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
982 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
983 */
Michael Ludwig08b260c2019-05-17 11:21:53 -0400984 if (imageFilter) {
985 SkMatrix modifiedCTM;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400986 sk_sp<SkImageFilter> modifiedFilter = as_IFB(imageFilter)->applyCTM(stashedMatrix,
987 &modifiedCTM);
988 if (as_IFB(modifiedFilter)->uniqueID() != as_IFB(imageFilter)->uniqueID()) {
Michael Ludwig08b260c2019-05-17 11:21:53 -0400989 // The original filter couldn't support the CTM entirely
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400990 SkASSERT(modifiedCTM.isScaleTranslate() || as_IFB(imageFilter)->canHandleComplexCTM());
Michael Ludwig08b260c2019-05-17 11:21:53 -0400991 modifiedRec = fMCRec;
992 this->internalSetMatrix(modifiedCTM);
993 SkPaint* p = lazyP.set(*paint);
994 p->setImageFilter(std::move(modifiedFilter));
995 imageFilter = p->getImageFilter();
996 paint = p;
997 }
998 // Else the filter didn't change, so modifiedCTM == stashedMatrix and there's nothing
999 // left to do since the stack already has that as the CTM.
reed8c30a812016-04-20 16:36:51 -07001000 }
reed8c30a812016-04-20 16:36:51 -07001001
junov@chromium.orga907ac32012-02-24 21:54:07 +00001002 // do this before we create the layer. We don't call the public save() since
1003 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001004 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001005
junov@chromium.orga907ac32012-02-24 21:54:07 +00001006 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001007 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001008 if (modifiedRec) {
1009 // In this case there will be no layer in which to stash the matrix so we need to
1010 // revert the prior MCRec to its earlier state.
1011 modifiedRec->fMatrix = stashedMatrix;
1012 }
reed2ff1fce2014-12-11 07:07:37 -08001013 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014 }
1015
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001016 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1017 // the clipRectBounds() call above?
1018 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001019 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001020 }
1021
reed8dc0ccb2015-03-20 06:32:52 -07001022 SkPixelGeometry geo = fProps.pixelGeometry();
1023 if (paint) {
reed76033be2015-03-14 10:54:31 -07001024 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001025 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001026 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001027 }
1028 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029
robertphillips5139e502016-07-19 05:10:40 -07001030 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001031 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001032 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001033 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001034 }
reedb2db8982014-11-13 12:41:02 -08001035
Mike Kleine083f7c2018-02-07 12:54:27 -05001036 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
Mike Reed1f3548c2019-07-12 12:53:11 -04001037 if (rec.fSaveLayerFlags & kF16ColorType) {
1038 info = info.makeColorType(kRGBA_F16_SkColorType);
1039 }
reed129ed1c2016-02-22 06:42:31 -08001040
Hal Canary704cd322016-11-07 14:13:52 -05001041 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001042 {
Florin Malita4571e492019-07-16 10:25:58 -04001043 SkASSERT(info.alphaType() != kOpaque_SkAlphaType);
reeddaa57bf2015-05-15 10:39:17 -07001044 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001045 const bool trackCoverage =
1046 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001047 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed910ca0f2018-04-25 13:04:05 -04001048 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001049 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001050 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1051 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001052 return;
reed61f501f2015-04-29 08:34:00 -07001053 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001054 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001055 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056
Mike Reedb43a3e02017-02-11 10:18:58 -05001057 // only have a "next" if this new layer doesn't affect the clip (rare)
1058 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059 fMCRec->fLayer = layer;
1060 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001061
Mike Reedc61abee2017-02-28 17:45:27 -05001062 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001063 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001064 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001065 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001066
Mike Reedc42a1cd2017-02-14 14:25:14 -05001067 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1068
1069 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1070 if (layer->fNext) {
1071 // need to punch a hole in the previous device, so we don't draw there, given that
1072 // the new top-layer will allow drawing to happen "below" it.
1073 SkRegion hole(ir);
1074 do {
1075 layer = layer->fNext;
1076 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1077 } while (layer->fNext);
1078 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001079}
1080
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001081int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001082 if (0xFF == alpha) {
1083 return this->saveLayer(bounds, nullptr);
1084 } else {
1085 SkPaint tmpPaint;
1086 tmpPaint.setAlpha(alpha);
1087 return this->saveLayer(bounds, &tmpPaint);
1088 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001089}
1090
Mike Reed148b7fd2018-12-18 17:38:18 -05001091void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1092 SkIRect devBounds;
1093 if (localBounds) {
1094 SkRect tmp;
1095 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1096 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1097 devBounds.setEmpty();
1098 }
1099 } else {
1100 devBounds = this->getDeviceClipBounds();
1101 }
1102 if (devBounds.isEmpty()) {
1103 return;
1104 }
1105
1106 SkBaseDevice* device = this->getTopDevice();
1107 if (nullptr == device) { // Do we still need this check???
1108 return;
1109 }
1110
1111 // need the bounds relative to the device itself
1112 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1113
Michael Ludwigac352122019-08-28 21:03:05 +00001114 // This is getting the special image from the current device, which is then drawn into (both by
1115 // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its
1116 // own device, we need to explicitly copy the back image contents so that its original content
1117 // is available when we splat it back later during restore.
1118 auto backImage = device->snapSpecial(devBounds, /* copy */ true);
Mike Reed148b7fd2018-12-18 17:38:18 -05001119 if (!backImage) {
1120 return;
1121 }
1122
1123 // we really need the save, so we can wack the fMCRec
1124 this->checkForDeferredSave();
1125
1126 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1127
1128 SkPaint paint;
1129 paint.setBlendMode(SkBlendMode::kClear);
Mike Reed9adc82c2019-04-23 10:28:13 -04001130 this->drawClippedToSaveBehind(paint);
Mike Reed148b7fd2018-12-18 17:38:18 -05001131}
1132
reed@android.com8a1c16f2008-12-17 15:59:43 +00001133void SkCanvas::internalRestore() {
1134 SkASSERT(fMCStack.count() != 0);
1135
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001136 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137 DeviceCM* layer = fMCRec->fLayer; // may be null
1138 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001139 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140
Mike Reed148b7fd2018-12-18 17:38:18 -05001141 // move this out before we do the actual restore
1142 auto backImage = std::move(fMCRec->fBackImage);
1143
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144 // now do the normal restore()
1145 fMCRec->~MCRec(); // balanced in save()
1146 fMCStack.pop_back();
1147 fMCRec = (MCRec*)fMCStack.back();
1148
Mike Reedc42a1cd2017-02-14 14:25:14 -05001149 if (fMCRec) {
1150 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1151 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001152
Mike Reed148b7fd2018-12-18 17:38:18 -05001153 if (backImage) {
1154 SkPaint paint;
1155 paint.setBlendMode(SkBlendMode::kDstOver);
1156 const int x = backImage->fLoc.x();
1157 const int y = backImage->fLoc.y();
1158 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1159 nullptr, SkMatrix::I());
1160 }
1161
reed@android.com8a1c16f2008-12-17 15:59:43 +00001162 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1163 since if we're being recorded, we don't want to record this (the
1164 recorder will have already recorded the restore).
1165 */
bsalomon49f085d2014-09-05 13:34:00 -07001166 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001167 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001168 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001169 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001170 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001171 layer->fPaint.get(),
1172 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001173 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001174 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001175 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001176 delete layer;
reedb679ca82015-04-07 04:40:48 -07001177 } else {
1178 // we're at the root
reeda499f902015-05-01 09:34:31 -07001179 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001180 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001181 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001183 }
msarettfbfa2582016-08-12 08:29:08 -07001184
1185 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001186 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001187 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1188 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189}
1190
reede8f30622016-03-23 18:59:25 -07001191sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001192 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001193 props = &fProps;
1194 }
1195 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001196}
1197
reede8f30622016-03-23 18:59:25 -07001198sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001199 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001200 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001201}
1202
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001203SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001204 return this->onImageInfo();
1205}
1206
1207SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001208 SkBaseDevice* dev = this->getDevice();
1209 if (dev) {
1210 return dev->imageInfo();
1211 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001212 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001213 }
1214}
1215
brianosman898235c2016-04-06 07:38:23 -07001216bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001217 return this->onGetProps(props);
1218}
1219
1220bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001221 SkBaseDevice* dev = this->getDevice();
1222 if (dev) {
1223 if (props) {
1224 *props = fProps;
1225 }
1226 return true;
1227 } else {
1228 return false;
1229 }
1230}
1231
reed6ceeebd2016-03-09 14:26:26 -08001232bool SkCanvas::peekPixels(SkPixmap* pmap) {
1233 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001234}
1235
reed884e97c2015-05-26 11:31:54 -07001236bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001237 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001238 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001239}
1240
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001241void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001242 SkPixmap pmap;
1243 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001244 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001245 }
1246 if (info) {
1247 *info = pmap.info();
1248 }
1249 if (rowBytes) {
1250 *rowBytes = pmap.rowBytes();
1251 }
1252 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001253 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001254 }
reed884e97c2015-05-26 11:31:54 -07001255 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001256}
1257
reed884e97c2015-05-26 11:31:54 -07001258bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001259 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001260 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001261}
1262
reed@android.com8a1c16f2008-12-17 15:59:43 +00001263/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001264
Mike Reed8bcd1282019-03-13 16:51:54 -04001265// In our current design/features, we should never have a layer (src) in a different colorspace
1266// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1267// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1268// colorspace.
1269static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1270 SkASSERT(src == dst);
1271}
1272
Florin Malita53f77bd2017-04-28 13:48:37 -04001273void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1274 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001276 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277 paint = &tmp;
1278 }
reed@google.com4b226022011-01-11 18:32:13 +00001279
Mike Reed38992392019-07-30 10:48:15 -04001280 DRAW_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001281
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001283 SkBaseDevice* dstDev = iter.fDevice;
Mike Reed8bcd1282019-03-13 16:51:54 -04001284 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1285 srcDev->imageInfo().colorSpace());
Mike Reed38992392019-07-30 10:48:15 -04001286 paint = &draw.paint();
reed@google.com76dd2772012-01-05 21:15:07 +00001287 SkImageFilter* filter = paint->getImageFilter();
1288 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001289 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001290 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1291 if (specialImage) {
Mike Reed8bcd1282019-03-13 16:51:54 -04001292 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1293 specialImage->getColorSpace());
Florin Malita53f77bd2017-04-28 13:48:37 -04001294 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1295 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001296 }
reed@google.com76dd2772012-01-05 21:15:07 +00001297 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001298 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001299 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 }
reeda2217ef2016-07-20 06:04:34 -07001301
Mike Reed38992392019-07-30 10:48:15 -04001302 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303}
1304
reed32704672015-12-16 08:27:10 -08001305/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001306
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001307void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001308 if (dx || dy) {
1309 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001310 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001311
reedfe69b502016-09-12 06:31:48 -07001312 // Translate shouldn't affect the is-scale-translateness of the matrix.
1313 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001314
Mike Reedc42a1cd2017-02-14 14:25:14 -05001315 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001316
reedfe69b502016-09-12 06:31:48 -07001317 this->didTranslate(dx,dy);
1318 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319}
1320
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001321void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001322 SkMatrix m;
1323 m.setScale(sx, sy);
1324 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325}
1326
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001327void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001328 SkMatrix m;
1329 m.setRotate(degrees);
1330 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001331}
1332
bungeman7438bfc2016-07-12 15:01:19 -07001333void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1334 SkMatrix m;
1335 m.setRotate(degrees, px, py);
1336 this->concat(m);
1337}
1338
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001339void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001340 SkMatrix m;
1341 m.setSkew(sx, sy);
1342 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001343}
1344
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001345void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001346 if (matrix.isIdentity()) {
1347 return;
1348 }
1349
reed2ff1fce2014-12-11 07:07:37 -08001350 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001351 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001352 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001353
Mike Reed7627fa52017-02-08 10:07:53 -05001354 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001355
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001356 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001357}
1358
reed8c30a812016-04-20 16:36:51 -07001359void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001360 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001361 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001362
Mike Reedc42a1cd2017-02-14 14:25:14 -05001363 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001364}
1365
1366void SkCanvas::setMatrix(const SkMatrix& matrix) {
1367 this->checkForDeferredSave();
1368 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001369 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001370}
1371
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001373 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001374}
1375
1376//////////////////////////////////////////////////////////////////////////////
1377
Mike Reedc1f77742016-12-09 09:00:50 -05001378void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001379 if (!rect.isFinite()) {
1380 return;
1381 }
reed2ff1fce2014-12-11 07:07:37 -08001382 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001383 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1384 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001385}
1386
Mike Reedc1f77742016-12-09 09:00:50 -05001387void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001388 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001389
Mike Reed7627fa52017-02-08 10:07:53 -05001390 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001391
reedc64eff52015-11-21 12:39:45 -08001392 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001393 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1394 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001395 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001396}
1397
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001398void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1399 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001400 if (fClipRestrictionRect.isEmpty()) {
1401 // we notify the device, but we *dont* resolve deferred saves (since we're just
1402 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001403 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001404 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001405 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001406 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001407 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001408 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001409 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1410 }
1411}
1412
Mike Reedc1f77742016-12-09 09:00:50 -05001413void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001414 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001415 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001416 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001417 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1418 } else {
1419 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001420 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001421}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001422
Mike Reedc1f77742016-12-09 09:00:50 -05001423void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001424 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001425
Brian Salomona3b45d42016-10-03 11:36:16 -04001426 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001427
Mike Reed7627fa52017-02-08 10:07:53 -05001428 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001429
Mike Reed20800c82017-11-15 16:09:04 -05001430 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1431 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001432 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001433}
1434
Mike Reedc1f77742016-12-09 09:00:50 -05001435void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001436 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001438
1439 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1440 SkRect r;
1441 if (path.isRect(&r)) {
1442 this->onClipRect(r, op, edgeStyle);
1443 return;
1444 }
1445 SkRRect rrect;
1446 if (path.isOval(&r)) {
1447 rrect.setOval(r);
1448 this->onClipRRect(rrect, op, edgeStyle);
1449 return;
1450 }
1451 if (path.isRRect(&rrect)) {
1452 this->onClipRRect(rrect, op, edgeStyle);
1453 return;
1454 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001455 }
robertphillips39f05382015-11-24 09:30:12 -08001456
1457 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001458}
1459
Mike Reedc1f77742016-12-09 09:00:50 -05001460void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001461 AutoValidateClip avc(this);
1462
Brian Salomona3b45d42016-10-03 11:36:16 -04001463 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001464
Mike Reed7627fa52017-02-08 10:07:53 -05001465 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466
Brian Salomona3b45d42016-10-03 11:36:16 -04001467 const SkPath* rasterClipPath = &path;
1468 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001469 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1470 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001471 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001472}
1473
Mike Reedc1f77742016-12-09 09:00:50 -05001474void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001475 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001476 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001477}
1478
Mike Reedc1f77742016-12-09 09:00:50 -05001479void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001480 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001481
reed@google.com5c3d1472011-02-22 19:12:23 +00001482 AutoValidateClip avc(this);
1483
Mike Reed20800c82017-11-15 16:09:04 -05001484 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001485 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486}
1487
reed@google.com819c9212011-02-23 18:56:55 +00001488#ifdef SK_DEBUG
1489void SkCanvas::validateClip() const {
1490 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001491 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001492 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001493 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001494 return;
1495 }
reed@google.com819c9212011-02-23 18:56:55 +00001496}
1497#endif
1498
Mike Reeda1361362017-03-07 09:37:29 -05001499bool SkCanvas::androidFramework_isClipAA() const {
1500 bool containsAA = false;
1501
1502 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1503
1504 return containsAA;
1505}
1506
1507class RgnAccumulator {
1508 SkRegion* fRgn;
1509public:
1510 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1511 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1512 SkIPoint origin = device->getOrigin();
1513 if (origin.x() | origin.y()) {
1514 rgn->translate(origin.x(), origin.y());
1515 }
1516 fRgn->op(*rgn, SkRegion::kUnion_Op);
1517 }
1518};
1519
1520void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1521 RgnAccumulator accum(rgn);
1522 SkRegion tmp;
1523
1524 rgn->setEmpty();
1525 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001526}
1527
reed@google.com5c3d1472011-02-22 19:12:23 +00001528///////////////////////////////////////////////////////////////////////////////
1529
reed@google.com754de5f2014-02-24 19:38:20 +00001530bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001531 return fMCRec->fRasterClip.isEmpty();
1532
1533 // TODO: should we only use the conservative answer in a recording canvas?
1534#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001535 SkBaseDevice* dev = this->getTopDevice();
1536 // if no device we return true
1537 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001538#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001539}
1540
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001541bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001542 SkBaseDevice* dev = this->getTopDevice();
1543 // if no device we return false
Dave Tapuska7139f132019-08-15 09:22:11 -04001544 return dev && dev->onGetClipType() == SkBaseDevice::ClipType::kRect;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001545}
1546
msarettfbfa2582016-08-12 08:29:08 -07001547static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1548#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1549 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1550 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1551 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1552 return 0xF != _mm_movemask_ps(mask);
1553#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1554 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1555 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1556 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1557 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1558#else
1559 SkRect devRectAsRect;
1560 SkRect devClipAsRect;
1561 devRect.store(&devRectAsRect.fLeft);
1562 devClip.store(&devClipAsRect.fLeft);
1563 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1564#endif
1565}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001566
msarettfbfa2582016-08-12 08:29:08 -07001567// It's important for this function to not be inlined. Otherwise the compiler will share code
1568// between the fast path and the slow path, resulting in two slow paths.
1569static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1570 const SkMatrix& matrix) {
1571 SkRect deviceRect;
1572 matrix.mapRect(&deviceRect, src);
1573 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1574}
1575
1576bool SkCanvas::quickReject(const SkRect& src) const {
1577#ifdef SK_DEBUG
1578 // Verify that fDeviceClipBounds are set properly.
1579 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001580 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001581 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001582 } else {
msarettfbfa2582016-08-12 08:29:08 -07001583 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001584 }
msarettfbfa2582016-08-12 08:29:08 -07001585
msarett9637ea92016-08-18 14:03:30 -07001586 // Verify that fIsScaleTranslate is set properly.
1587 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001588#endif
1589
msarett9637ea92016-08-18 14:03:30 -07001590 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001591 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1592 }
1593
1594 // We inline the implementation of mapScaleTranslate() for the fast path.
1595 float sx = fMCRec->fMatrix.getScaleX();
1596 float sy = fMCRec->fMatrix.getScaleY();
1597 float tx = fMCRec->fMatrix.getTranslateX();
1598 float ty = fMCRec->fMatrix.getTranslateY();
1599 Sk4f scale(sx, sy, sx, sy);
1600 Sk4f trans(tx, ty, tx, ty);
1601
1602 // Apply matrix.
1603 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1604
1605 // Make sure left < right, top < bottom.
1606 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1607 Sk4f min = Sk4f::Min(ltrb, rblt);
1608 Sk4f max = Sk4f::Max(ltrb, rblt);
1609 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1610 // ARM this sequence generates the fastest (a single instruction).
1611 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1612
1613 // Check if the device rect is NaN or outside the clip.
1614 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615}
1616
reed@google.com3b3e8952012-08-16 20:53:31 +00001617bool SkCanvas::quickReject(const SkPath& path) const {
1618 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001619}
1620
Mike Klein83c8dd92017-11-28 17:08:45 -05001621SkRect SkCanvas::getLocalClipBounds() const {
1622 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001623 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001624 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001625 }
1626
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001627 SkMatrix inverse;
1628 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001629 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001630 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001631 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001632
Mike Reed42e8c532017-01-23 14:09:13 -05001633 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001634 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001635 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001636
Mike Reedb57b9312018-04-23 12:12:54 -04001637 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001638 inverse.mapRect(&bounds, r);
1639 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001640}
1641
Mike Klein83c8dd92017-11-28 17:08:45 -05001642SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001643 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001644}
1645
reed@android.com8a1c16f2008-12-17 15:59:43 +00001646const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001647 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648}
1649
Brian Osman11052242016-10-27 14:47:55 -04001650GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001651 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001652 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001653}
1654
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001655GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001656 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001657 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001658}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001659
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001660void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1661 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001662 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001663 if (outer.isEmpty()) {
1664 return;
1665 }
1666 if (inner.isEmpty()) {
1667 this->drawRRect(outer, paint);
1668 return;
1669 }
1670
1671 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001672 // be able to return ...
1673 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001674 //
1675 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001676 if (!outer.getBounds().contains(inner.getBounds())) {
1677 return;
1678 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001679
1680 this->onDrawDRRect(outer, inner, paint);
1681}
1682
reed41af9662015-01-05 07:49:08 -08001683void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001684 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001685 this->onDrawPaint(paint);
1686}
1687
1688void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001689 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001690 // To avoid redundant logic in our culling code and various backends, we always sort rects
1691 // before passing them along.
1692 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001693}
1694
Mike Reedd5674082019-04-19 15:00:47 -04001695void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1696 TRACE_EVENT0("skia", TRACE_FUNC);
1697 this->onDrawBehind(paint);
1698}
1699
msarettdca352e2016-08-26 06:37:45 -07001700void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001701 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001702 if (region.isEmpty()) {
1703 return;
1704 }
1705
1706 if (region.isRect()) {
1707 return this->drawIRect(region.getBounds(), paint);
1708 }
1709
1710 this->onDrawRegion(region, paint);
1711}
1712
reed41af9662015-01-05 07:49:08 -08001713void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001714 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001715 // To avoid redundant logic in our culling code and various backends, we always sort rects
1716 // before passing them along.
1717 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001718}
1719
1720void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001721 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001722 this->onDrawRRect(rrect, paint);
1723}
1724
1725void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001726 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001727 this->onDrawPoints(mode, count, pts, paint);
1728}
1729
Mike Reede88a1cb2017-03-17 09:50:46 -04001730void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1731 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001732 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001733 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001734 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1735 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001736 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001737}
1738
1739void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001740 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001741 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001742 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1743}
1744
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001745void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1746 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001747 TRACE_EVENT0("skia", TRACE_FUNC);
1748 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001749 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001750 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1751}
1752
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001753void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1754 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001755 TRACE_EVENT0("skia", TRACE_FUNC);
1756 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001757 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001758 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001759}
1760
1761void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001762 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001763 this->onDrawPath(path, paint);
1764}
1765
reeda85d4d02015-05-06 12:56:48 -07001766void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001767 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001768 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001769 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001770}
1771
Mike Reedc4e31092018-01-30 11:15:27 -05001772// Returns true if the rect can be "filled" : non-empty and finite
1773static bool fillable(const SkRect& r) {
1774 SkScalar w = r.width();
1775 SkScalar h = r.height();
1776 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1777}
1778
reede47829b2015-08-06 10:02:53 -07001779void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1780 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001781 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001782 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001783 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001784 return;
1785 }
1786 this->onDrawImageRect(image, &src, dst, paint, constraint);
1787}
reed41af9662015-01-05 07:49:08 -08001788
reed84984ef2015-07-17 07:09:43 -07001789void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1790 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001791 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001792 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001793}
1794
Brian Salomonf08002c2018-10-26 16:15:46 -04001795void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001796 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001797 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001798 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001799}
reede47829b2015-08-06 10:02:53 -07001800
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001801namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001802class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001803public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001804 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1805 if (!origPaint) {
1806 return;
1807 }
1808 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1809 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1810 }
1811 if (origPaint->getMaskFilter()) {
1812 fPaint.writable()->setMaskFilter(nullptr);
1813 }
1814 if (origPaint->isAntiAlias()) {
1815 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001816 }
1817 }
1818
1819 const SkPaint* get() const {
1820 return fPaint;
1821 }
1822
1823private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001824 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001825};
1826} // namespace
1827
reed4c21dc52015-06-25 12:32:03 -07001828void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1829 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001830 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001831 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001832 if (dst.isEmpty()) {
1833 return;
1834 }
msarett552bca92016-08-03 06:53:26 -07001835 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001836 LatticePaint latticePaint(paint);
1837 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001838 } else {
reede47829b2015-08-06 10:02:53 -07001839 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001840 }
reed4c21dc52015-06-25 12:32:03 -07001841}
1842
msarett16882062016-08-16 09:31:08 -07001843void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1844 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001845 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001846 RETURN_ON_NULL(image);
1847 if (dst.isEmpty()) {
1848 return;
1849 }
msarett71df2d72016-09-30 12:41:42 -07001850
1851 SkIRect bounds;
1852 Lattice latticePlusBounds = lattice;
1853 if (!latticePlusBounds.fBounds) {
1854 bounds = SkIRect::MakeWH(image->width(), image->height());
1855 latticePlusBounds.fBounds = &bounds;
1856 }
1857
1858 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001859 LatticePaint latticePaint(paint);
1860 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001861 } else {
1862 this->drawImageRect(image, dst, paint);
1863 }
1864}
1865
reed41af9662015-01-05 07:49:08 -08001866void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001867 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001868 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001869 return;
1870 }
reed41af9662015-01-05 07:49:08 -08001871 this->onDrawBitmap(bitmap, dx, dy, paint);
1872}
1873
reede47829b2015-08-06 10:02:53 -07001874void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001875 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001876 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001877 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001878 return;
1879 }
reede47829b2015-08-06 10:02:53 -07001880 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001881}
1882
reed84984ef2015-07-17 07:09:43 -07001883void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1884 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001885 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001886}
1887
reede47829b2015-08-06 10:02:53 -07001888void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1889 SrcRectConstraint constraint) {
1890 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1891 constraint);
1892}
reede47829b2015-08-06 10:02:53 -07001893
reed41af9662015-01-05 07:49:08 -08001894void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1895 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001896 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001897 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001898 return;
1899 }
msarett552bca92016-08-03 06:53:26 -07001900 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001901 LatticePaint latticePaint(paint);
1902 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001903 } else {
reeda5517e22015-07-14 10:54:12 -07001904 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001905 }
reed41af9662015-01-05 07:49:08 -08001906}
1907
msarettc573a402016-08-02 08:05:56 -07001908void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1909 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001910 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001911 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001912 return;
1913 }
msarett71df2d72016-09-30 12:41:42 -07001914
1915 SkIRect bounds;
1916 Lattice latticePlusBounds = lattice;
1917 if (!latticePlusBounds.fBounds) {
1918 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1919 latticePlusBounds.fBounds = &bounds;
1920 }
1921
1922 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001923 LatticePaint latticePaint(paint);
1924 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001925 } else {
msarett16882062016-08-16 09:31:08 -07001926 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001927 }
msarettc573a402016-08-02 08:05:56 -07001928}
1929
reed71c3c762015-06-24 10:29:17 -07001930void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001931 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001932 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001933 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001934 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001935 if (count <= 0) {
1936 return;
1937 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001938 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001939 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001940 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001941}
1942
reedf70b5312016-03-04 16:36:20 -08001943void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001944 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001945 if (key) {
1946 this->onDrawAnnotation(rect, key, value);
1947 }
1948}
1949
reede47829b2015-08-06 10:02:53 -07001950void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1951 const SkPaint* paint, SrcRectConstraint constraint) {
1952 if (src) {
1953 this->drawImageRect(image, *src, dst, paint, constraint);
1954 } else {
1955 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1956 dst, paint, constraint);
1957 }
1958}
1959void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1960 const SkPaint* paint, SrcRectConstraint constraint) {
1961 if (src) {
1962 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1963 } else {
1964 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1965 dst, paint, constraint);
1966 }
1967}
1968
Mike Reed4204da22017-05-17 08:53:36 -04001969void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001970 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001971 this->onDrawShadowRec(path, rec);
1972}
1973
1974void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1975 SkPaint paint;
1976 const SkRect& pathBounds = path.getBounds();
1977
Mike Reed38992392019-07-30 10:48:15 -04001978 DRAW_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001979 while (iter.next()) {
1980 iter.fDevice->drawShadow(path, rec);
1981 }
Mike Reed38992392019-07-30 10:48:15 -04001982 DRAW_END
Mike Reed4204da22017-05-17 08:53:36 -04001983}
1984
Michael Ludwig390f0cc2019-03-19 09:16:38 -04001985void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
Michael Ludwiga595f862019-08-27 15:25:49 -04001986 QuadAAFlags aaFlags, const SkColor4f& color,
1987 SkBlendMode mode) {
Michael Ludwig390f0cc2019-03-19 09:16:38 -04001988 TRACE_EVENT0("skia", TRACE_FUNC);
1989 // Make sure the rect is sorted before passing it along
1990 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
1991}
1992
1993void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
1994 const SkPoint dstClips[],
1995 const SkMatrix preViewMatrices[],
1996 const SkPaint* paint,
1997 SrcRectConstraint constraint) {
1998 TRACE_EVENT0("skia", TRACE_FUNC);
1999 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2000}
2001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002002//////////////////////////////////////////////////////////////////////////////
2003// These are the virtual drawing methods
2004//////////////////////////////////////////////////////////////////////////////
2005
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002006void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002007 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002008 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2009 }
2010}
2011
reed41af9662015-01-05 07:49:08 -08002012void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002013 this->internalDrawPaint(paint);
2014}
2015
2016void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Mike Reed38992392019-07-30 10:48:15 -04002017 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018
2019 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002020 iter.fDevice->drawPaint(draw.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002021 }
2022
Mike Reed38992392019-07-30 10:48:15 -04002023 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002024}
2025
reed41af9662015-01-05 07:49:08 -08002026void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2027 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002028 if ((long)count <= 0) {
2029 return;
2030 }
2031
Mike Reed822128b2017-02-28 16:41:03 -05002032 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002033 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002034 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002035 // special-case 2 points (common for drawing a single line)
2036 if (2 == count) {
2037 r.set(pts[0], pts[1]);
2038 } else {
Mike Reed92b33352019-08-24 19:39:13 -04002039 r.setBounds(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002040 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002041 if (!r.isFinite()) {
2042 return;
2043 }
Mike Reed822128b2017-02-28 16:41:03 -05002044 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002045 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2046 return;
2047 }
2048 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002049 }
reed@google.coma584aed2012-05-16 14:06:02 +00002050
halcanary96fcdcc2015-08-27 07:41:13 -07002051 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002052
Mike Reed38992392019-07-30 10:48:15 -04002053 DRAW_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002054
reed@android.com8a1c16f2008-12-17 15:59:43 +00002055 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002056 iter.fDevice->drawPoints(mode, count, pts, draw.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002057 }
reed@google.com4b226022011-01-11 18:32:13 +00002058
Mike Reed38992392019-07-30 10:48:15 -04002059 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002060}
2061
reed4a167172016-08-18 17:15:25 -07002062static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
Mike Reed9dc0b9e2019-07-29 17:52:48 -04002063 return paint.getImageFilter() != nullptr;
reed4a167172016-08-18 17:15:25 -07002064}
2065
reed41af9662015-01-05 07:49:08 -08002066void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002067 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002068 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002069 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002070 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002071 return;
2072 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002073 }
reed@google.com4b226022011-01-11 18:32:13 +00002074
reed4a167172016-08-18 17:15:25 -07002075 if (needs_autodrawlooper(this, paint)) {
Mike Reed38992392019-07-30 10:48:15 -04002076 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002077
reed4a167172016-08-18 17:15:25 -07002078 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002079 iter.fDevice->drawRect(r, draw.paint());
reed4a167172016-08-18 17:15:25 -07002080 }
2081
Mike Reed38992392019-07-30 10:48:15 -04002082 DRAW_END
Mike Reed49f8da02018-08-27 10:48:52 -04002083 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002084 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002085 SkDrawIter iter(this);
2086 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002087 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002088 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002089 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002090}
2091
msarett44df6512016-08-25 13:54:30 -07002092void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002093 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002094 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002095 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002096 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2097 return;
2098 }
msarett44df6512016-08-25 13:54:30 -07002099 }
2100
Mike Reed38992392019-07-30 10:48:15 -04002101 DRAW_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002102
2103 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002104 iter.fDevice->drawRegion(region, draw.paint());
msarett44df6512016-08-25 13:54:30 -07002105 }
2106
Mike Reed38992392019-07-30 10:48:15 -04002107 DRAW_END
msarett44df6512016-08-25 13:54:30 -07002108}
2109
Mike Reedd5674082019-04-19 15:00:47 -04002110void SkCanvas::onDrawBehind(const SkPaint& paint) {
2111 SkIRect bounds;
2112 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2113 for (;;) {
2114 const MCRec* rec = (const MCRec*)iter.prev();
2115 if (!rec) {
2116 return; // no backimages, so nothing to draw
2117 }
2118 if (rec->fBackImage) {
2119 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2120 rec->fBackImage->fImage->width(),
2121 rec->fBackImage->fImage->height());
2122 break;
2123 }
2124 }
2125
Mike Reed38992392019-07-30 10:48:15 -04002126 DRAW_BEGIN(paint, nullptr)
Mike Reedd5674082019-04-19 15:00:47 -04002127
2128 while (iter.next()) {
2129 SkBaseDevice* dev = iter.fDevice;
2130
Mike Reedd5674082019-04-19 15:00:47 -04002131 dev->save();
2132 // We use clipRegion because it is already defined to operate in dev-space
2133 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2134 // but we don't want that, so we undo that before calling in.
2135 SkRegion rgn(bounds.makeOffset(dev->fOrigin.fX, dev->fOrigin.fY));
2136 dev->clipRegion(rgn, SkClipOp::kIntersect);
Mike Reed38992392019-07-30 10:48:15 -04002137 dev->drawPaint(draw.paint());
Mike Reed9adc82c2019-04-23 10:28:13 -04002138 dev->restore(fMCRec->fMatrix);
Mike Reedd5674082019-04-19 15:00:47 -04002139 }
2140
Mike Reed38992392019-07-30 10:48:15 -04002141 DRAW_END
Mike Reedd5674082019-04-19 15:00:47 -04002142}
2143
reed41af9662015-01-05 07:49:08 -08002144void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002145 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002146 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002147 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002148 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002149 return;
2150 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002151 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002152
Mike Reed38992392019-07-30 10:48:15 -04002153 DRAW_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002154
2155 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002156 iter.fDevice->drawOval(oval, draw.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002157 }
2158
Mike Reed38992392019-07-30 10:48:15 -04002159 DRAW_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002160}
2161
bsalomonac3aa242016-08-19 11:25:19 -07002162void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2163 SkScalar sweepAngle, bool useCenter,
2164 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002165 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002166 if (paint.canComputeFastBounds()) {
2167 SkRect storage;
2168 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002169 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002170 return;
2171 }
bsalomonac3aa242016-08-19 11:25:19 -07002172 }
2173
Mike Reed38992392019-07-30 10:48:15 -04002174 DRAW_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002175
2176 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002177 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, draw.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002178 }
2179
Mike Reed38992392019-07-30 10:48:15 -04002180 DRAW_END
bsalomonac3aa242016-08-19 11:25:19 -07002181}
2182
reed41af9662015-01-05 07:49:08 -08002183void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002184 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002185 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002186 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2187 return;
2188 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002189 }
2190
2191 if (rrect.isRect()) {
2192 // call the non-virtual version
2193 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002194 return;
2195 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002196 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002197 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2198 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002199 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002200
Mike Reed38992392019-07-30 10:48:15 -04002201 DRAW_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002202
2203 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002204 iter.fDevice->drawRRect(rrect, draw.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002205 }
2206
Mike Reed38992392019-07-30 10:48:15 -04002207 DRAW_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002208}
2209
Mike Reed822128b2017-02-28 16:41:03 -05002210void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002211 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002212 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002213 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2214 return;
2215 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002216 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002217
Mike Reed38992392019-07-30 10:48:15 -04002218 DRAW_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002219
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002220 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002221 iter.fDevice->drawDRRect(outer, inner, draw.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002222 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002223
Mike Reed38992392019-07-30 10:48:15 -04002224 DRAW_END
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002225}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002226
reed41af9662015-01-05 07:49:08 -08002227void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002228 if (!path.isFinite()) {
2229 return;
2230 }
2231
Mike Reed822128b2017-02-28 16:41:03 -05002232 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002233 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002234 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002235 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2236 return;
2237 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002238 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002239
Mike Reed822128b2017-02-28 16:41:03 -05002240 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002241 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002242 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002243 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002244 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002245 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002246
Mike Reed38992392019-07-30 10:48:15 -04002247 DRAW_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002248
2249 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002250 iter.fDevice->drawPath(path, draw.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002251 }
2252
Mike Reed38992392019-07-30 10:48:15 -04002253 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002254}
2255
reed262a71b2015-12-05 13:07:27 -08002256bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002257 if (!paint.getImageFilter()) {
2258 return false;
2259 }
2260
2261 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002262 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002263 return false;
2264 }
2265
2266 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2267 // Once we can filter and the filter will return a result larger than itself, we should be
2268 // able to remove this constraint.
2269 // skbug.com/4526
2270 //
2271 SkPoint pt;
2272 ctm.mapXY(x, y, &pt);
2273 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2274 return ir.contains(fMCRec->fRasterClip.getBounds());
2275}
2276
Mike Reedf441cfc2018-04-11 14:50:16 -04002277// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2278// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2279// null.
2280static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2281 if (paintParam) {
2282 *real = *paintParam;
2283 real->setStyle(SkPaint::kFill_Style);
2284 real->setPathEffect(nullptr);
2285 paintParam = real;
2286 }
2287 return paintParam;
2288}
2289
reeda85d4d02015-05-06 12:56:48 -07002290void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002291 SkPaint realPaint;
2292 paint = init_image_paint(&realPaint, paint);
2293
reeda85d4d02015-05-06 12:56:48 -07002294 SkRect bounds = SkRect::MakeXYWH(x, y,
2295 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002296 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002297 SkRect tmp = bounds;
2298 if (paint) {
2299 paint->computeFastBounds(tmp, &tmp);
2300 }
2301 if (this->quickReject(tmp)) {
2302 return;
2303 }
reeda85d4d02015-05-06 12:56:48 -07002304 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002305 // At this point we need a real paint object. If the caller passed null, then we should
2306 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2307 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2308 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002309
reeda2217ef2016-07-20 06:04:34 -07002310 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002311 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2312 *paint);
2313 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002314 special = this->getDevice()->makeSpecial(image);
2315 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002316 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002317 }
2318 }
2319
Mike Reed38992392019-07-30 10:48:15 -04002320 DRAW_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed262a71b2015-12-05 13:07:27 -08002321
reeda85d4d02015-05-06 12:56:48 -07002322 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002323 const SkPaint& pnt = draw.paint();
reeda2217ef2016-07-20 06:04:34 -07002324 if (special) {
2325 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002326 iter.fDevice->ctm().mapXY(x, y, &pt);
2327 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002328 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002329 SkScalarRoundToInt(pt.fY), pnt,
2330 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002331 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002332 iter.fDevice->drawImageRect(
2333 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2334 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002335 }
reeda85d4d02015-05-06 12:56:48 -07002336 }
halcanary9d524f22016-03-29 09:03:52 -07002337
Mike Reed38992392019-07-30 10:48:15 -04002338 DRAW_END
piotaixrb5fae932014-09-24 13:03:30 -07002339}
2340
reed41af9662015-01-05 07:49:08 -08002341void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002342 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002343 SkPaint realPaint;
2344 paint = init_image_paint(&realPaint, paint);
2345
halcanary96fcdcc2015-08-27 07:41:13 -07002346 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002347 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002348 if (paint) {
2349 paint->computeFastBounds(dst, &storage);
2350 }
2351 if (this->quickReject(storage)) {
2352 return;
2353 }
reeda85d4d02015-05-06 12:56:48 -07002354 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002355 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002356
Mike Reed38992392019-07-30 10:48:15 -04002357 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002358
reeda85d4d02015-05-06 12:56:48 -07002359 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002360 iter.fDevice->drawImageRect(image, src, dst, draw.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002361 }
halcanary9d524f22016-03-29 09:03:52 -07002362
Mike Reed38992392019-07-30 10:48:15 -04002363 DRAW_END
piotaixrb5fae932014-09-24 13:03:30 -07002364}
2365
reed41af9662015-01-05 07:49:08 -08002366void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002367 SkDEBUGCODE(bitmap.validate();)
2368
reed33366972015-10-08 09:22:02 -07002369 if (bitmap.drawsNothing()) {
2370 return;
2371 }
2372
Mike Reedf441cfc2018-04-11 14:50:16 -04002373 SkPaint realPaint;
2374 init_image_paint(&realPaint, paint);
2375 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002376
Mike Reed822128b2017-02-28 16:41:03 -05002377 SkRect bounds;
2378 bitmap.getBounds(&bounds);
2379 bounds.offset(x, y);
2380 bool canFastBounds = paint->canComputeFastBounds();
2381 if (canFastBounds) {
2382 SkRect storage;
2383 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002384 return;
2385 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002386 }
reed@google.com4b226022011-01-11 18:32:13 +00002387
reeda2217ef2016-07-20 06:04:34 -07002388 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002389 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2390 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002391 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002392 special = this->getDevice()->makeSpecial(bitmap);
2393 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002394 drawAsSprite = false;
2395 }
2396 }
2397
Mike Reed38992392019-07-30 10:48:15 -04002398 DRAW_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002399
2400 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002401 const SkPaint& pnt = draw.paint();
reeda2217ef2016-07-20 06:04:34 -07002402 if (special) {
reed262a71b2015-12-05 13:07:27 -08002403 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002404 iter.fDevice->ctm().mapXY(x, y, &pt);
2405 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002406 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002407 SkScalarRoundToInt(pt.fY), pnt,
2408 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002409 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002410 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2411 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2412 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002413 }
reed33366972015-10-08 09:22:02 -07002414 }
msarettfbfa2582016-08-12 08:29:08 -07002415
Mike Reed38992392019-07-30 10:48:15 -04002416 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002417}
2418
reed@google.com9987ec32011-09-07 11:57:52 +00002419// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002420void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002421 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002422 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002423 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002424 return;
2425 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002426
halcanary96fcdcc2015-08-27 07:41:13 -07002427 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002428 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002429 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2430 return;
2431 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002432 }
reed@google.com3d608122011-11-21 15:16:16 +00002433
reed@google.com33535f32012-09-25 15:37:50 +00002434 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002435 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002436 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002437 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002438
Mike Reed38992392019-07-30 10:48:15 -04002439 DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002440
reed@google.com33535f32012-09-25 15:37:50 +00002441 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002442 iter.fDevice->drawBitmapRect(bitmap, src, dst, draw.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002443 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002444
Mike Reed38992392019-07-30 10:48:15 -04002445 DRAW_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446}
2447
reed41af9662015-01-05 07:49:08 -08002448void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002449 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002450 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002451 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002452}
2453
reed4c21dc52015-06-25 12:32:03 -07002454void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2455 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002456 SkPaint realPaint;
2457 paint = init_image_paint(&realPaint, paint);
2458
halcanary96fcdcc2015-08-27 07:41:13 -07002459 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002460 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002461 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2462 return;
2463 }
reed@google.com3d608122011-11-21 15:16:16 +00002464 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002465 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002466
Mike Reed38992392019-07-30 10:48:15 -04002467 DRAW_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002468
reed4c21dc52015-06-25 12:32:03 -07002469 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002470 iter.fDevice->drawImageNine(image, center, dst, draw.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002471 }
halcanary9d524f22016-03-29 09:03:52 -07002472
Mike Reed38992392019-07-30 10:48:15 -04002473 DRAW_END
reed@google.com9987ec32011-09-07 11:57:52 +00002474}
2475
reed41af9662015-01-05 07:49:08 -08002476void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2477 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002478 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002479 SkPaint realPaint;
2480 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002481
halcanary96fcdcc2015-08-27 07:41:13 -07002482 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002483 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002484 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2485 return;
2486 }
reed4c21dc52015-06-25 12:32:03 -07002487 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002488 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002489
Mike Reed38992392019-07-30 10:48:15 -04002490 DRAW_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002491
reed4c21dc52015-06-25 12:32:03 -07002492 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002493 iter.fDevice->drawBitmapNine(bitmap, center, dst, draw.paint());
reed4c21dc52015-06-25 12:32:03 -07002494 }
halcanary9d524f22016-03-29 09:03:52 -07002495
Mike Reed38992392019-07-30 10:48:15 -04002496 DRAW_END
reed@google.com9987ec32011-09-07 11:57:52 +00002497}
2498
msarett16882062016-08-16 09:31:08 -07002499void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2500 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002501 SkPaint realPaint;
2502 paint = init_image_paint(&realPaint, paint);
2503
msarett16882062016-08-16 09:31:08 -07002504 if (nullptr == paint || paint->canComputeFastBounds()) {
2505 SkRect storage;
2506 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2507 return;
2508 }
2509 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002510 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002511
Mike Reed38992392019-07-30 10:48:15 -04002512 DRAW_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002513
2514 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002515 iter.fDevice->drawImageLattice(image, lattice, dst, draw.paint());
msarett16882062016-08-16 09:31:08 -07002516 }
2517
Mike Reed38992392019-07-30 10:48:15 -04002518 DRAW_END
msarett16882062016-08-16 09:31:08 -07002519}
2520
2521void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2522 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002523 SkPaint realPaint;
2524 paint = init_image_paint(&realPaint, paint);
2525
msarett16882062016-08-16 09:31:08 -07002526 if (nullptr == paint || paint->canComputeFastBounds()) {
2527 SkRect storage;
2528 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2529 return;
2530 }
2531 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002532 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002533
Mike Reed38992392019-07-30 10:48:15 -04002534 DRAW_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002535
2536 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002537 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, draw.paint());
msarett16882062016-08-16 09:31:08 -07002538 }
2539
Mike Reed38992392019-07-30 10:48:15 -04002540 DRAW_END
msarett16882062016-08-16 09:31:08 -07002541}
2542
fmalita00d5c2c2014-08-21 08:53:26 -07002543void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2544 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002545 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002546 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002547 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002548 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002549 SkRect tmp;
2550 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2551 return;
2552 }
2553 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002554 }
2555
fmalita024f9962015-03-03 19:08:17 -08002556 // We cannot filter in the looper as we normally do, because the paint is
2557 // incomplete at this point (text-related attributes are embedded within blob run paints).
Mike Reed38992392019-07-30 10:48:15 -04002558 DRAW_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002559
fmalitaaa1b9122014-08-28 14:32:24 -07002560 while (iter.next()) {
Mike Reed38992392019-07-30 10:48:15 -04002561 fScratchGlyphRunBuilder->drawTextBlob(draw.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002562 }
2563
Mike Reed38992392019-07-30 10:48:15 -04002564 DRAW_END
fmalita00d5c2c2014-08-21 08:53:26 -07002565}
2566
Mike Reed358fcad2018-11-23 15:27:51 -05002567// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002568void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002569 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2570 TRACE_EVENT0("skia", TRACE_FUNC);
2571 if (byteLength) {
2572 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002573 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002574 }
2575}
Mike Reed4f81bb72019-01-23 09:23:00 -05002576
fmalita00d5c2c2014-08-21 08:53:26 -07002577void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2578 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002579 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002580 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002581 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002582 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002583}
reed@google.come0d9ce82014-04-23 04:00:17 +00002584
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002585void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002586 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Mike Reed38992392019-07-30 10:48:15 -04002587 DRAW_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002588
2589 while (iter.next()) {
2590 // In the common case of one iteration we could std::move vertices here.
Mike Reed38992392019-07-30 10:48:15 -04002591 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, draw.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002592 }
2593
Mike Reed38992392019-07-30 10:48:15 -04002594 DRAW_END
Brian Salomon199fb872017-02-06 09:41:10 -05002595}
2596
dandovb3c9d1c2014-08-12 08:34:29 -07002597void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002598 const SkPoint texCoords[4], SkBlendMode bmode,
2599 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002600 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002601 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002602 return;
2603 }
mtklein6cfa73a2014-08-13 13:33:49 -07002604
Mike Reedfaba3712016-11-03 14:45:31 -04002605 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002606}
2607
2608void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002609 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002610 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002611 // Since a patch is always within the convex hull of the control points, we discard it when its
2612 // bounding rectangle is completely outside the current clip.
2613 SkRect bounds;
Mike Reed92b33352019-08-24 19:39:13 -04002614 bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002615 if (this->quickReject(bounds)) {
2616 return;
2617 }
mtklein6cfa73a2014-08-13 13:33:49 -07002618
Mike Reed38992392019-07-30 10:48:15 -04002619 DRAW_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002620
dandovecfff212014-08-04 10:02:00 -07002621 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002622 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002623 }
mtklein6cfa73a2014-08-13 13:33:49 -07002624
Mike Reed38992392019-07-30 10:48:15 -04002625 DRAW_END
dandovecfff212014-08-04 10:02:00 -07002626}
2627
reeda8db7282015-07-07 10:22:31 -07002628void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002629#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002630 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002631#endif
reede3b38ce2016-01-08 09:18:44 -08002632 RETURN_ON_NULL(dr);
2633 if (x || y) {
2634 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2635 this->onDrawDrawable(dr, &matrix);
2636 } else {
2637 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002638 }
2639}
2640
reeda8db7282015-07-07 10:22:31 -07002641void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002642#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002643 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002644#endif
reede3b38ce2016-01-08 09:18:44 -08002645 RETURN_ON_NULL(dr);
2646 if (matrix && matrix->isIdentity()) {
2647 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002648 }
reede3b38ce2016-01-08 09:18:44 -08002649 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002650}
2651
2652void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002653 // drawable bounds are no longer reliable (e.g. android displaylist)
2654 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002655 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002656}
2657
reed71c3c762015-06-24 10:29:17 -07002658void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002659 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002660 const SkRect* cull, const SkPaint* paint) {
2661 if (cull && this->quickReject(*cull)) {
2662 return;
2663 }
2664
2665 SkPaint pnt;
2666 if (paint) {
2667 pnt = *paint;
2668 }
halcanary9d524f22016-03-29 09:03:52 -07002669
Mike Reed38992392019-07-30 10:48:15 -04002670 DRAW_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002671 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002672 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002673 }
Mike Reed38992392019-07-30 10:48:15 -04002674 DRAW_END
reed71c3c762015-06-24 10:29:17 -07002675}
2676
reedf70b5312016-03-04 16:36:20 -08002677void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2678 SkASSERT(key);
2679
2680 SkPaint paint;
Mike Reed38992392019-07-30 10:48:15 -04002681 DRAW_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002682 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002683 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002684 }
Mike Reed38992392019-07-30 10:48:15 -04002685 DRAW_END
reedf70b5312016-03-04 16:36:20 -08002686}
2687
Michael Ludwiga595f862019-08-27 15:25:49 -04002688void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2689 const SkColor4f& color, SkBlendMode mode) {
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002690 SkASSERT(r.isSorted());
2691
2692 // If this used a paint, it would be a filled color with blend mode, which does not
2693 // need to use an autodraw loop, so use SkDrawIter directly.
2694 if (this->quickReject(r)) {
2695 return;
2696 }
2697
Michael Ludwiga4b44882019-08-28 14:34:58 -04002698 this->predrawNotify(&r, nullptr, false);
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002699 SkDrawIter iter(this);
2700 while(iter.next()) {
2701 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2702 }
2703}
2704
2705void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2706 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2707 const SkPaint* paint, SrcRectConstraint constraint) {
Michael Ludwiga4b44882019-08-28 14:34:58 -04002708 if (count <= 0) {
2709 // Nothing to draw
2710 return;
2711 }
2712
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002713 SkPaint realPaint;
2714 init_image_paint(&realPaint, paint);
2715
Michael Ludwiga4b44882019-08-28 14:34:58 -04002716 // We could calculate the set's dstRect union to always check quickReject(), but we can't reject
2717 // individual entries and Chromium's occlusion culling already makes it likely that at least one
2718 // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1),
2719 // or we need it for the autolooper (since it greatly improves image filter perf).
2720 bool needsAutoLooper = needs_autodrawlooper(this, realPaint);
2721 bool setBoundsValid = count == 1 || needsAutoLooper;
2722 SkRect setBounds = imageSet[0].fDstRect;
2723 if (imageSet[0].fMatrixIndex >= 0) {
2724 // Account for the per-entry transform that is applied prior to the CTM when drawing
2725 preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds);
Michael Ludwig977b50a2019-08-27 13:23:20 -04002726 }
Michael Ludwiga4b44882019-08-28 14:34:58 -04002727 if (needsAutoLooper) {
2728 for (int i = 1; i < count; ++i) {
2729 SkRect entryBounds = imageSet[i].fDstRect;
2730 if (imageSet[i].fMatrixIndex >= 0) {
2731 preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds);
2732 }
2733 setBounds.joinPossiblyEmptyRect(entryBounds);
2734 }
2735 }
2736
2737 // If we happen to have the draw bounds, though, might as well check quickReject().
2738 if (setBoundsValid && realPaint.canComputeFastBounds()) {
2739 SkRect tmp;
2740 if (this->quickReject(realPaint.computeFastBounds(setBounds, &tmp))) {
2741 return;
2742 }
2743 }
2744
2745 if (needsAutoLooper) {
2746 SkASSERT(setBoundsValid);
2747 DRAW_BEGIN(realPaint, &setBounds)
2748 while (iter.next()) {
2749 iter.fDevice->drawEdgeAAImageSet(
2750 imageSet, count, dstClips, preViewMatrices, draw.paint(), constraint);
2751 }
2752 DRAW_END
2753 } else {
2754 this->predrawNotify();
2755 SkDrawIter iter(this);
2756 while(iter.next()) {
2757 iter.fDevice->drawEdgeAAImageSet(
2758 imageSet, count, dstClips, preViewMatrices, realPaint, constraint);
2759 }
2760 }
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002761}
2762
reed@android.com8a1c16f2008-12-17 15:59:43 +00002763//////////////////////////////////////////////////////////////////////////////
2764// These methods are NOT virtual, and therefore must call back into virtual
2765// methods, rather than actually drawing themselves.
2766//////////////////////////////////////////////////////////////////////////////
2767
reed374772b2016-10-05 17:33:02 -07002768void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002771 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772 this->drawPaint(paint);
2773}
2774
2775void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002776 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2778}
2779
Mike Reed3661bc92017-02-22 13:21:42 -05002780void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782 pts[0].set(x0, y0);
2783 pts[1].set(x1, y1);
2784 this->drawPoints(kLines_PointMode, 2, pts, paint);
2785}
2786
Mike Reed3661bc92017-02-22 13:21:42 -05002787void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002788 if (radius < 0) {
2789 radius = 0;
2790 }
2791
2792 SkRect r;
Mike Reed92b33352019-08-24 19:39:13 -04002793 r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002794 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795}
2796
2797void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2798 const SkPaint& paint) {
2799 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002800 SkRRect rrect;
2801 rrect.setRectXY(r, rx, ry);
2802 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002803 } else {
2804 this->drawRect(r, paint);
2805 }
2806}
2807
reed@android.com8a1c16f2008-12-17 15:59:43 +00002808void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2809 SkScalar sweepAngle, bool useCenter,
2810 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002811 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002812 if (oval.isEmpty() || !sweepAngle) {
2813 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814 }
bsalomon21af9ca2016-08-25 12:29:23 -07002815 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816}
2817
reed@android.comf76bacf2009-05-13 14:00:33 +00002818///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002819#ifdef SK_DISABLE_SKPICTURE
2820void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002821
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002822
2823void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2824 const SkPaint* paint) {}
2825#else
Mike Klein88d90712018-01-27 17:30:04 +00002826/**
2827 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2828 * against the playback cost of recursing into the subpicture to get at its actual ops.
2829 *
2830 * For now we pick a conservatively small value, though measurement (and other heuristics like
2831 * the type of ops contained) may justify changing this value.
2832 */
2833#define kMaxPictureOpsToUnrollInsteadOfRef 1
2834
reedd5fa1a42014-08-09 11:08:05 -07002835void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002836 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002837 RETURN_ON_NULL(picture);
2838
reede3b38ce2016-01-08 09:18:44 -08002839 if (matrix && matrix->isIdentity()) {
2840 matrix = nullptr;
2841 }
Mike Klein88d90712018-01-27 17:30:04 +00002842 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2843 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2844 picture->playback(this);
2845 } else {
2846 this->onDrawPicture(picture, matrix, paint);
2847 }
reedd5fa1a42014-08-09 11:08:05 -07002848}
robertphillips9b14f262014-06-04 05:40:44 -07002849
reedd5fa1a42014-08-09 11:08:05 -07002850void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2851 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002852 if (!paint || paint->canComputeFastBounds()) {
2853 SkRect bounds = picture->cullRect();
2854 if (paint) {
2855 paint->computeFastBounds(bounds, &bounds);
2856 }
2857 if (matrix) {
2858 matrix->mapRect(&bounds);
2859 }
2860 if (this->quickReject(bounds)) {
2861 return;
2862 }
2863 }
2864
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002865 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002866 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002867}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002868#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002869
reed@android.com8a1c16f2008-12-17 15:59:43 +00002870///////////////////////////////////////////////////////////////////////////////
2871///////////////////////////////////////////////////////////////////////////////
2872
reed3aafe112016-08-18 12:45:34 -07002873SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002874 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002875
2876 SkASSERT(canvas);
2877
reed3aafe112016-08-18 12:45:34 -07002878 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002879 fDone = !fImpl->next();
2880}
2881
2882SkCanvas::LayerIter::~LayerIter() {
2883 fImpl->~SkDrawIter();
2884}
2885
2886void SkCanvas::LayerIter::next() {
2887 fDone = !fImpl->next();
2888}
2889
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002890SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002891 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002892}
2893
2894const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002895 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002896}
2897
2898const SkPaint& SkCanvas::LayerIter::paint() const {
2899 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002900 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002901 paint = &fDefaultPaint;
2902 }
2903 return *paint;
2904}
2905
Mike Reedca37f322018-03-08 13:22:16 -05002906SkIRect SkCanvas::LayerIter::clipBounds() const {
2907 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002908}
2909
reed@android.com8a1c16f2008-12-17 15:59:43 +00002910int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2911int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002912
2913///////////////////////////////////////////////////////////////////////////////
2914
Brian Osmane8a98632019-04-10 10:26:10 -04002915SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2916SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2917SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2918SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2919
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002920SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2921 const SkRect& dstRect, int matrixIndex, float alpha,
2922 unsigned aaFlags, bool hasClip)
2923 : fImage(std::move(image))
2924 , fSrcRect(srcRect)
2925 , fDstRect(dstRect)
2926 , fMatrixIndex(matrixIndex)
2927 , fAlpha(alpha)
2928 , fAAFlags(aaFlags)
2929 , fHasClip(hasClip) {}
2930
2931SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2932 const SkRect& dstRect, float alpha, unsigned aaFlags)
2933 : fImage(std::move(image))
2934 , fSrcRect(srcRect)
2935 , fDstRect(dstRect)
2936 , fAlpha(alpha)
2937 , fAAFlags(aaFlags) {}
2938
2939///////////////////////////////////////////////////////////////////////////////
2940
Mike Reed5df49342016-11-12 08:06:55 -06002941std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002942 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002943 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002944 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002945 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002946
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002947 SkBitmap bitmap;
2948 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002949 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002950 }
Mike Reed12f77342017-11-08 11:19:52 -05002951
2952 return props ?
2953 skstd::make_unique<SkCanvas>(bitmap, *props) :
2954 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002955}
reedd5fa1a42014-08-09 11:08:05 -07002956
2957///////////////////////////////////////////////////////////////////////////////
2958
Florin Malitaee424ac2016-12-01 12:47:59 -05002959SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002960 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002961
Florin Malita439ace92016-12-02 12:05:41 -05002962SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002963 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002964
Herb Derbyefe39bc2018-05-01 17:06:20 -04002965SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002966 : INHERITED(device) {}
2967
Florin Malitaee424ac2016-12-01 12:47:59 -05002968SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2969 (void)this->INHERITED::getSaveLayerStrategy(rec);
2970 return kNoLayer_SaveLayerStrategy;
2971}
2972
Mike Reed148b7fd2018-12-18 17:38:18 -05002973bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2974 return false;
2975}
2976
Florin Malitaee424ac2016-12-01 12:47:59 -05002977///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002978
reed73603f32016-09-20 08:42:38 -07002979static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2980static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2981static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2982static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2983static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2984static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002985
2986///////////////////////////////////////////////////////////////////////////////////////////////////
2987
2988SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2989 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002990 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002991 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2992 SkIPoint origin = dev->getOrigin();
2993 SkMatrix ctm = this->getTotalMatrix();
2994 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2995
2996 SkIRect clip = fMCRec->fRasterClip.getBounds();
2997 clip.offset(-origin.x(), -origin.y());
Mike Reed92b33352019-08-24 19:39:13 -04002998 if (!clip.intersect({0, 0, dev->width(), dev->height()})) {
Mike Reed356f7c22017-01-10 11:58:39 -05002999 clip.setEmpty();
3000 }
3001
3002 fAllocator->updateHandle(handle, ctm, clip);
3003 return handle;
3004 }
3005 return nullptr;
3006}
3007
3008static bool install(SkBitmap* bm, const SkImageInfo& info,
3009 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04003010 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05003011}
3012
3013SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3014 SkBitmap* bm) {
3015 SkRasterHandleAllocator::Rec rec;
3016 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3017 return nullptr;
3018 }
3019 return rec.fHandle;
3020}
3021
3022std::unique_ptr<SkCanvas>
3023SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3024 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04003025 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05003026 return nullptr;
3027 }
3028
3029 SkBitmap bm;
3030 Handle hndl;
3031
3032 if (rec) {
3033 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3034 } else {
3035 hndl = alloc->allocBitmap(info, &bm);
3036 }
3037 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3038}
Mike Reed7c9c9e42018-01-03 09:23:34 -05003039
3040///////////////////////////////////////////////////////////////////////////////////////////////////