blob: 08ed025fffa956c7fde7ef878ef3dc5d37c5e319 [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
Hal Canaryc640d0d2018-06-13 09:59:02 -04008#include "SkCanvas.h"
9
Herb Derby73fe7b02017-02-08 15:12:19 -050010#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +000011#include "SkBitmapDevice.h"
reedd5fa1a42014-08-09 11:08:05 -070012#include "SkCanvasPriv.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040013#include "SkClipOpPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070014#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070015#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDraw.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkDrawLooper.h"
Herb Derby41f4f312018-06-06 17:45:53 +000018#include "SkGlyphCache.h"
19#include "SkGlyphRun.h"
piotaixrb5fae932014-09-24 13:03:30 -070020#include "SkImage.h"
senorblanco900c3672016-04-27 11:31:23 -070021#include "SkImageFilter.h"
22#include "SkImageFilterCache.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040023#include "SkImage_Base.h"
msarettc573a402016-08-02 08:05:56 -070024#include "SkLatticeIter.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040025#include "SkMSAN.h"
Mike Reed5df49342016-11-12 08:06:55 -060026#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080027#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000028#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050029#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070030#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070031#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070032#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040033#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000034#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040035#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000036#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050037#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080038#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000039#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040040#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000041#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040042#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070043#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000044#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040045#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080046#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040047#include "SkVertices.h"
48
bungemand3ebb482015-08-05 13:57:49 -070049#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000050
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080052#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050053#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000054#endif
55
reede3b38ce2016-01-08 09:18:44 -080056#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050057#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080058
Mike Reed139e5e02017-03-08 11:29:33 -050059///////////////////////////////////////////////////////////////////////////////////////////////////
60
reedc83a2972015-07-16 07:40:45 -070061/*
62 * Return true if the drawing this rect would hit every pixels in the canvas.
63 *
64 * Returns false if
65 * - rect does not contain the canvas' bounds
66 * - paint is not fill
67 * - paint would blur or otherwise change the coverage of the rect
68 */
69bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
70 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070071 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
72 (int)kNone_ShaderOverrideOpacity,
73 "need_matching_enums0");
74 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
75 (int)kOpaque_ShaderOverrideOpacity,
76 "need_matching_enums1");
77 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
78 (int)kNotOpaque_ShaderOverrideOpacity,
79 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070080
81 const SkISize size = this->getBaseLayerSize();
82 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050083
84 // if we're clipped at all, we can't overwrite the entire surface
85 {
86 SkBaseDevice* base = this->getDevice();
87 SkBaseDevice* top = this->getTopDevice();
88 if (base != top) {
89 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
90 }
91 if (!base->clipIsWideOpen()) {
92 return false;
93 }
reedc83a2972015-07-16 07:40:45 -070094 }
95
96 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070097 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070098 return false; // conservative
99 }
halcanaryc5769b22016-08-10 07:13:21 -0700100
101 SkRect devRect;
102 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
103 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700104 return false;
105 }
106 }
107
108 if (paint) {
109 SkPaint::Style paintStyle = paint->getStyle();
110 if (!(paintStyle == SkPaint::kFill_Style ||
111 paintStyle == SkPaint::kStrokeAndFill_Style)) {
112 return false;
113 }
114 if (paint->getMaskFilter() || paint->getLooper()
115 || paint->getPathEffect() || paint->getImageFilter()) {
116 return false; // conservative
117 }
118 }
119 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
120}
121
122///////////////////////////////////////////////////////////////////////////////////////////////////
123
reed@google.comda17f752012-08-16 18:27:05 +0000124// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125//#define SK_TRACE_SAVERESTORE
126
127#ifdef SK_TRACE_SAVERESTORE
128 static int gLayerCounter;
129 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
130 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
131
132 static int gRecCounter;
133 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
134 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
135
136 static int gCanvasCounter;
137 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
138 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
139#else
140 #define inc_layer()
141 #define dec_layer()
142 #define inc_rec()
143 #define dec_rec()
144 #define inc_canvas()
145 #define dec_canvas()
146#endif
147
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000148typedef SkTLazy<SkPaint> SkLazyPaint;
149
reedc83a2972015-07-16 07:40:45 -0700150void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000151 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700152 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
153 ? SkSurface::kDiscard_ContentChangeMode
154 : SkSurface::kRetain_ContentChangeMode);
155 }
156}
157
158void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
159 ShaderOverrideOpacity overrideOpacity) {
160 if (fSurfaceBase) {
161 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
162 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
163 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
164 // and therefore we don't care which mode we're in.
165 //
166 if (fSurfaceBase->outstandingImageSnapshot()) {
167 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
168 mode = SkSurface::kDiscard_ContentChangeMode;
169 }
170 }
171 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000172 }
173}
174
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000177/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 The clip/matrix/proc are fields that reflect the top of the save/restore
179 stack. Whenever the canvas changes, it marks a dirty flag, and then before
180 these are used (assuming we're not on a layer) we rebuild these cache
181 values: they reflect the top of the save stack, but translated and clipped
182 by the device's XY offset and bitmap-bounds.
183*/
184struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400185 DeviceCM* fNext;
186 sk_sp<SkBaseDevice> fDevice;
187 SkRasterClip fClip;
188 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
189 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400190 sk_sp<SkImage> fClipImage;
191 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192
Florin Malita53f77bd2017-04-28 13:48:37 -0400193 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000194 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700195 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400196 , fDevice(std::move(device))
197 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700198 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000199 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400200 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400201 {}
reed@google.com4b226022011-01-11 18:32:13 +0000202
mtkleinfeaadee2015-04-08 11:25:48 -0700203 void reset(const SkIRect& bounds) {
204 SkASSERT(!fPaint);
205 SkASSERT(!fNext);
206 SkASSERT(fDevice);
207 fClip.setRect(bounds);
208 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209};
210
211/* This is the record we keep for each save/restore level in the stack.
212 Since a level optionally copies the matrix and/or stack, we have pointers
213 for these fields. If the value is copied for this level, the copy is
214 stored in the ...Storage field, and the pointer points to that. If the
215 value is not copied for this level, we ignore ...Storage, and just point
216 at the corresponding value in the previous level in the stack.
217*/
218class SkCanvas::MCRec {
219public:
reedd9544982014-09-09 18:46:22 -0700220 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 /* If there are any layers in the stack, this points to the top-most
222 one that is at or below this level in the stack (so we know what
223 bitmap/device to draw into from this level. This value is NOT
224 reference counted, since the real owner is either our fLayer field,
225 or a previous one in a lower level.)
226 */
Mike Reeda1361362017-03-07 09:37:29 -0500227 DeviceCM* fTopLayer;
228 SkConservativeClip fRasterClip;
229 SkMatrix fMatrix;
230 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231
Mike Reeda1361362017-03-07 09:37:29 -0500232 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700233 fLayer = nullptr;
234 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800235 fMatrix.reset();
236 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700237
reedd9544982014-09-09 18:46:22 -0700238 // don't bother initializing fNext
239 inc_rec();
240 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400241 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700242 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700243 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800244 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 // don't bother initializing fNext
247 inc_rec();
248 }
249 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700250 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 dec_rec();
252 }
mtkleinfeaadee2015-04-08 11:25:48 -0700253
254 void reset(const SkIRect& bounds) {
255 SkASSERT(fLayer);
256 SkASSERT(fDeferredSaveCount == 0);
257
258 fMatrix.reset();
259 fRasterClip.setRect(bounds);
260 fLayer->reset(bounds);
261 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262};
263
Mike Reeda1361362017-03-07 09:37:29 -0500264class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265public:
Mike Reeda1361362017-03-07 09:37:29 -0500266 SkDrawIter(SkCanvas* canvas)
267 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
268 {}
reed@google.com4b226022011-01-11 18:32:13 +0000269
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000271 const DeviceCM* rec = fCurrLayer;
272 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400273 fDevice = rec->fDevice.get();
274 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700276 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 return true;
278 }
279 return false;
280 }
reed@google.com4b226022011-01-11 18:32:13 +0000281
reed@google.com6f8f2922011-03-04 22:27:10 +0000282 int getX() const { return fDevice->getOrigin().x(); }
283 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000285
Mike Reed99330ba2017-02-22 11:01:08 -0500286 SkBaseDevice* fDevice;
287
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 const DeviceCM* fCurrLayer;
290 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291};
292
Florin Malita713b8ef2017-04-28 10:57:24 -0400293#define FOR_EACH_TOP_DEVICE( code ) \
294 do { \
295 DeviceCM* layer = fMCRec->fTopLayer; \
296 while (layer) { \
297 SkBaseDevice* device = layer->fDevice.get(); \
298 if (device) { \
299 code; \
300 } \
301 layer = layer->fNext; \
302 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500303 } while (0)
304
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305/////////////////////////////////////////////////////////////////////////////
306
reeddbc3cef2015-04-29 12:18:57 -0700307static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
308 return lazy->isValid() ? lazy->get() : lazy->set(orig);
309}
310
311/**
312 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700313 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700314 */
reedd053ce92016-03-22 10:17:23 -0700315static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700316 SkImageFilter* imgf = paint.getImageFilter();
317 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700318 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700319 }
320
reedd053ce92016-03-22 10:17:23 -0700321 SkColorFilter* imgCFPtr;
322 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700323 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700324 }
reedd053ce92016-03-22 10:17:23 -0700325 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700326
327 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700328 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700329 // there is no existing paint colorfilter, so we can just return the imagefilter's
330 return imgCF;
331 }
332
333 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
334 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500335 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700336}
337
senorblanco87e066e2015-10-28 11:23:36 -0700338/**
339 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
340 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
341 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
342 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
343 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
344 * conservative "effective" bounds based on the settings in the paint... with one exception. This
345 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
346 * deliberately ignored.
347 */
348static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
349 const SkRect& rawBounds,
350 SkRect* storage) {
351 SkPaint tmpUnfiltered(paint);
352 tmpUnfiltered.setImageFilter(nullptr);
353 if (tmpUnfiltered.canComputeFastBounds()) {
354 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
355 } else {
356 return rawBounds;
357 }
358}
359
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360class AutoDrawLooper {
361public:
senorblanco87e066e2015-10-28 11:23:36 -0700362 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
363 // paint. It's used to determine the size of the offscreen layer for filters.
364 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700365 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700366 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000367 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700368 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000369 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700370 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000371 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372
reedd053ce92016-03-22 10:17:23 -0700373 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700374 if (simplifiedCF) {
375 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700376 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700377 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700378 fPaint = paint;
379 }
380
381 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700382 /**
383 * We implement ImageFilters for a given draw by creating a layer, then applying the
384 * imagefilter to the pixels of that layer (its backing surface/image), and then
385 * we call restore() to xfer that layer to the main canvas.
386 *
387 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
388 * 2. Generate the src pixels:
389 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
390 * return (fPaint). We then draw the primitive (using srcover) into a cleared
391 * buffer/surface.
392 * 3. Restore the layer created in #1
393 * The imagefilter is passed the buffer/surface from the layer (now filled with the
394 * src pixels of the primitive). It returns a new "filtered" buffer, which we
395 * draw onto the previous layer using the xfermode from the original paint.
396 */
reed@google.com8926b162012-03-23 15:36:36 +0000397 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500398 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700399 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700400 SkRect storage;
401 if (rawBounds) {
402 // Make rawBounds include all paint outsets except for those due to image filters.
403 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
404 }
reedbfd5f172016-01-07 11:28:08 -0800405 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700406 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700407 fTempLayerForImageFilter = true;
408 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000409 }
410
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000411 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500412 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000413 fIsSimple = false;
414 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700415 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000416 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400417 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000418 }
419 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000420
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700422 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000423 fCanvas->internalRestore();
424 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000425 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000427
reed@google.com4e2b3d32011-04-07 14:18:59 +0000428 const SkPaint& paint() const {
429 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400430 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000431 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000433
Ben Wagner2c312c42018-06-27 14:46:46 -0400434 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000435 if (fDone) {
436 return false;
437 } else if (fIsSimple) {
438 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000439 return !fPaint->nothingToDraw();
440 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400441 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000442 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000443 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000444
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500446 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700447 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000448 SkCanvas* fCanvas;
449 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000450 const SkPaint* fPaint;
451 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700452 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000453 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000454 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000455 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400456 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000457
Ben Wagner2c312c42018-06-27 14:46:46 -0400458 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459};
460
Ben Wagner2c312c42018-06-27 14:46:46 -0400461bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700462 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000463 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400464 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000465
reeddbc3cef2015-04-29 12:18:57 -0700466 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
467 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400468 // never want our downstream clients (i.e. devices) to see loopers
469 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000470
reed5c476fb2015-04-20 08:04:21 -0700471 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700472 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700473 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000474 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000475
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000476 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000477 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000478 return false;
479 }
reed@google.com129ec222012-05-15 13:24:09 +0000480 fPaint = paint;
481
482 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400483 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000484 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000485 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000486 return true;
487}
488
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489////////// macros to place around the internal draw calls //////////////////
490
reed3aafe112016-08-18 12:45:34 -0700491#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
492 this->predrawNotify(); \
493 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400494 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800495 SkDrawIter iter(this);
496
497
Ben Wagner2c312c42018-06-27 14:46:46 -0400498#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000499 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700500 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400501 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000502 SkDrawIter iter(this);
503
Ben Wagner2c312c42018-06-27 14:46:46 -0400504#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000505 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700506 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400507 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000508 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000509
Ben Wagner2c312c42018-06-27 14:46:46 -0400510#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700511 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700512 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400513 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700514 SkDrawIter iter(this);
515
reed@google.com4e2b3d32011-04-07 14:18:59 +0000516#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517
518////////////////////////////////////////////////////////////////////////////
519
msarettfbfa2582016-08-12 08:29:08 -0700520static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
521 if (bounds.isEmpty()) {
522 return SkRect::MakeEmpty();
523 }
524
525 // Expand bounds out by 1 in case we are anti-aliasing. We store the
526 // bounds as floats to enable a faster quick reject implementation.
527 SkRect dst;
528 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
529 return dst;
530}
531
mtkleinfeaadee2015-04-08 11:25:48 -0700532void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
533 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700534 fMCRec->reset(bounds);
535
536 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500537 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400538 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700539 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700540 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700541}
542
Hal Canary363a3f82018-10-04 11:04:48 -0400543void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000544 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800545 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700546 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000547
548 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500549 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500550 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700551 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552
reeda499f902015-05-01 09:34:31 -0700553 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
554 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400555 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700556
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000558
halcanary96fcdcc2015-08-27 07:41:13 -0700559 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000560
reedf92c8662014-08-18 08:02:43 -0700561 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700562 // The root device and the canvas should always have the same pixel geometry
563 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800564 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700565 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500566
Mike Reedc42a1cd2017-02-14 14:25:14 -0500567 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700568 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400569
Herb Derby59d997a2018-06-07 12:44:09 -0400570 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571}
572
reed@google.comcde92112011-07-06 20:00:52 +0000573SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000574 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700575 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000576{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000577 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000578
Hal Canary363a3f82018-10-04 11:04:48 -0400579 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000580}
581
reed96a857e2015-01-25 10:33:58 -0800582SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000583 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800584 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000585{
586 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400587 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400588 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700589}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000590
Hal Canary363a3f82018-10-04 11:04:48 -0400591SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700592 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700593 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700594{
595 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700596
Mike Reed566e53c2017-03-10 10:49:45 -0500597 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400598 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700599}
600
Herb Derbyefe39bc2018-05-01 17:06:20 -0400601SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000602 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700603 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000604{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000605 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700606
Hal Canary363a3f82018-10-04 11:04:48 -0400607 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700608}
609
reed4a8126e2014-09-22 07:29:03 -0700610SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700611 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700612 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700613{
614 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700615
Mike Reed910ca0f2018-04-25 13:04:05 -0400616 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400617 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700618}
reed29c857d2014-09-21 10:25:07 -0700619
Mike Reed356f7c22017-01-10 11:58:39 -0500620SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
621 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700622 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
623 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500624 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700625{
626 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700627
Mike Reed910ca0f2018-04-25 13:04:05 -0400628 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400629 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000630}
631
Mike Reed356f7c22017-01-10 11:58:39 -0500632SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
633
Matt Sarett31f99ce2017-04-11 08:46:01 -0400634#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
635SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
636 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
637 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
638 , fAllocator(nullptr)
639{
640 inc_canvas();
641
642 SkBitmap tmp(bitmap);
643 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400644 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400645 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400646}
647#endif
648
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649SkCanvas::~SkCanvas() {
650 // free up the contents of our deque
651 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000652
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653 this->internalRestore(); // restore the last, since we're going away
654
halcanary385fe4d2015-08-26 13:07:48 -0700655 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000656
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657 dec_canvas();
658}
659
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000660SkMetaData& SkCanvas::getMetaData() {
661 // metadata users are rare, so we lazily allocate it. If that changes we
662 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700663 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000664 fMetaData = new SkMetaData;
665 }
666 return *fMetaData;
667}
668
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669///////////////////////////////////////////////////////////////////////////////
670
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000671void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700672 this->onFlush();
673}
674
675void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000676 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000677 if (device) {
678 device->flush();
679 }
680}
681
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000682SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000683 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000684 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
685}
686
senorblancoafc7cce2016-02-02 18:44:15 -0800687SkIRect SkCanvas::getTopLayerBounds() const {
688 SkBaseDevice* d = this->getTopDevice();
689 if (!d) {
690 return SkIRect::MakeEmpty();
691 }
692 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
693}
694
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000695SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000697 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000698 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400699 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000700}
701
Florin Malita0ed3b642017-01-13 16:56:38 +0000702SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400703 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000704}
705
Mike Reed353196f2017-07-21 11:01:18 -0400706bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000707 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400708 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000709}
710
Mike Reed353196f2017-07-21 11:01:18 -0400711bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
712 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400713}
714
715bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
716 SkPixmap pm;
717 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
718}
719
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000720bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400721 SkPixmap pm;
722 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700723 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000724 }
725 return false;
726}
727
Matt Sarett03dd6d52017-01-23 12:15:09 -0500728bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000729 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000730 SkBaseDevice* device = this->getDevice();
731 if (!device) {
732 return false;
733 }
734
Matt Sarett03dd6d52017-01-23 12:15:09 -0500735 // This check gives us an early out and prevents generation ID churn on the surface.
736 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
737 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
738 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
739 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000740 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000741
Matt Sarett03dd6d52017-01-23 12:15:09 -0500742 // Tell our owning surface to bump its generation ID.
743 const bool completeOverwrite =
744 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700745 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700746
Matt Sarett03dd6d52017-01-23 12:15:09 -0500747 // This can still fail, most notably in the case of a invalid color type or alpha type
748 // conversion. We could pull those checks into this function and avoid the unnecessary
749 // generation ID bump. But then we would be performing those checks twice, since they
750 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400751 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000752}
reed@google.com51df9e32010-12-23 19:29:18 +0000753
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754//////////////////////////////////////////////////////////////////////////////
755
reed2ff1fce2014-12-11 07:07:37 -0800756void SkCanvas::checkForDeferredSave() {
757 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800758 this->doSave();
759 }
760}
761
reedf0090cb2014-11-26 08:55:51 -0800762int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800763#ifdef SK_DEBUG
764 int count = 0;
765 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
766 for (;;) {
767 const MCRec* rec = (const MCRec*)iter.next();
768 if (!rec) {
769 break;
770 }
771 count += 1 + rec->fDeferredSaveCount;
772 }
773 SkASSERT(count == fSaveCount);
774#endif
775 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800776}
777
778int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800779 fSaveCount += 1;
780 fMCRec->fDeferredSaveCount += 1;
781 return this->getSaveCount() - 1; // return our prev value
782}
783
784void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800785 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700786
787 SkASSERT(fMCRec->fDeferredSaveCount > 0);
788 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800789 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800790}
791
792void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800793 if (fMCRec->fDeferredSaveCount > 0) {
794 SkASSERT(fSaveCount > 1);
795 fSaveCount -= 1;
796 fMCRec->fDeferredSaveCount -= 1;
797 } else {
798 // check for underflow
799 if (fMCStack.count() > 1) {
800 this->willRestore();
801 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700802 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800803 this->internalRestore();
804 this->didRestore();
805 }
reedf0090cb2014-11-26 08:55:51 -0800806 }
807}
808
809void SkCanvas::restoreToCount(int count) {
810 // sanity check
811 if (count < 1) {
812 count = 1;
813 }
mtkleinf0f14112014-12-12 08:46:25 -0800814
reedf0090cb2014-11-26 08:55:51 -0800815 int n = this->getSaveCount() - count;
816 for (int i = 0; i < n; ++i) {
817 this->restore();
818 }
819}
820
reed2ff1fce2014-12-11 07:07:37 -0800821void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700823 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000825
Mike Reedc42a1cd2017-02-14 14:25:14 -0500826 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827}
828
reed4960eee2015-12-18 07:09:18 -0800829bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400830 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831}
832
reed4960eee2015-12-18 07:09:18 -0800833bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700834 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500835 SkIRect clipBounds = this->getDeviceClipBounds();
836 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000837 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000838 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000839
reed96e657d2015-03-10 17:30:07 -0700840 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
841
Robert Phillips12078432018-05-17 11:17:39 -0400842 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
843 // If the image filter DAG affects transparent black then we will need to render
844 // out to the clip bounds
845 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000846 }
Robert Phillips12078432018-05-17 11:17:39 -0400847
848 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700849 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700851 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400852 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400854 inputSaveLayerBounds = clipBounds;
855 }
856
857 if (imageFilter) {
858 // expand the clip bounds by the image filter DAG to include extra content that might
859 // be required by the image filters.
860 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
861 SkImageFilter::kReverse_MapDirection,
862 &inputSaveLayerBounds);
863 }
864
865 SkIRect clippedSaveLayerBounds;
866 if (bounds) {
867 // For better or for worse, user bounds currently act as a hard clip on the layer's
868 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
869 clippedSaveLayerBounds = inputSaveLayerBounds;
870 } else {
871 // If there are no user bounds, we don't want to artificially restrict the resulting
872 // layer bounds, so allow the expanded clip bounds free reign.
873 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800875
876 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400877 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800878 if (BoundsAffectsClip(saveLayerFlags)) {
879 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
880 fMCRec->fRasterClip.setEmpty();
881 fDeviceClipBounds.setEmpty();
882 }
883 return false;
884 }
Robert Phillips12078432018-05-17 11:17:39 -0400885 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000886
reed4960eee2015-12-18 07:09:18 -0800887 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700888 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400889 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
890 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000891 }
892
893 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400894 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000895 }
Robert Phillips12078432018-05-17 11:17:39 -0400896
junov@chromium.orga907ac32012-02-24 21:54:07 +0000897 return true;
898}
899
reed4960eee2015-12-18 07:09:18 -0800900int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
901 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000902}
903
reed70ee31b2015-12-10 13:44:45 -0800904int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800905 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
906}
907
Cary Clarke041e312018-03-06 13:00:52 -0500908int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700909 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400910 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
911 // no need for the layer (or any of the draws until the matching restore()
912 this->save();
913 this->clipRect({0,0,0,0});
914 } else {
915 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
916 fSaveCount += 1;
917 this->internalSaveLayer(rec, strategy);
918 }
reed4960eee2015-12-18 07:09:18 -0800919 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800920}
921
reeda2217ef2016-07-20 06:04:34 -0700922void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500923 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500924 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700925 SkDraw draw;
926 SkRasterClip rc;
927 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
928 if (!dst->accessPixels(&draw.fDst)) {
929 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800930 }
reeda2217ef2016-07-20 06:04:34 -0700931 draw.fMatrix = &SkMatrix::I();
932 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800933
934 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500935 if (filter) {
936 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
937 }
reeda2217ef2016-07-20 06:04:34 -0700938
Mike Reedc42a1cd2017-02-14 14:25:14 -0500939 int x = src->getOrigin().x() - dstOrigin.x();
940 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700941 auto special = src->snapSpecial();
942 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400943 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700944 }
robertphillips7354a4b2015-12-16 05:08:27 -0800945}
reed70ee31b2015-12-10 13:44:45 -0800946
Mike Kleine083f7c2018-02-07 12:54:27 -0500947static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500948 // Need to force L32 for now if we have an image filter.
949 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
950 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500951 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800952 }
Mike Klein649fb732018-02-26 15:09:16 -0500953
954 SkColorType ct = prev.colorType();
955 if (prev.bytesPerPixel() <= 4) {
956 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
957 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
958 ct = kN32_SkColorType;
959 }
960 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800961}
962
reed4960eee2015-12-18 07:09:18 -0800963void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700964 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800965 const SkRect* bounds = rec.fBounds;
966 const SkPaint* paint = rec.fPaint;
967 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
968
reed8c30a812016-04-20 16:36:51 -0700969 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400970 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700971 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400972 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700973 SkMatrix remainder;
974 SkSize scale;
975 /*
976 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
977 * but they do handle scaling. To accommodate this, we do the following:
978 *
979 * 1. Stash off the current CTM
980 * 2. Decompose the CTM into SCALE and REMAINDER
981 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
982 * contains the REMAINDER
983 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
984 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
985 * of the original imagefilter, and draw that (via drawSprite)
986 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
987 *
988 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
989 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
990 */
reed96a04f32016-04-25 09:25:15 -0700991 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -0700992 stashedMatrix.decomposeScale(&scale, &remainder))
993 {
994 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -0400995 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -0700996 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
997 SkPaint* p = lazyP.set(*paint);
998 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
999 SkFilterQuality::kLow_SkFilterQuality,
1000 sk_ref_sp(imageFilter)));
1001 imageFilter = p->getImageFilter();
1002 paint = p;
1003 }
reed8c30a812016-04-20 16:36:51 -07001004
junov@chromium.orga907ac32012-02-24 21:54:07 +00001005 // do this before we create the layer. We don't call the public save() since
1006 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001007 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001008
junov@chromium.orga907ac32012-02-24 21:54:07 +00001009 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001010 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001011 if (modifiedRec) {
1012 // In this case there will be no layer in which to stash the matrix so we need to
1013 // revert the prior MCRec to its earlier state.
1014 modifiedRec->fMatrix = stashedMatrix;
1015 }
reed2ff1fce2014-12-11 07:07:37 -08001016 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001017 }
1018
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001019 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1020 // the clipRectBounds() call above?
1021 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001022 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001023 }
1024
reed8dc0ccb2015-03-20 06:32:52 -07001025 SkPixelGeometry geo = fProps.pixelGeometry();
1026 if (paint) {
reed76033be2015-03-14 10:54:31 -07001027 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001028 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001029 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001030 }
1031 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032
robertphillips5139e502016-07-19 05:10:40 -07001033 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001034 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001035 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001036 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001037 }
reedb2db8982014-11-13 12:41:02 -08001038
Mike Kleine083f7c2018-02-07 12:54:27 -05001039 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
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 {
reed70ee31b2015-12-10 13:44:45 -08001043 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001044 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001045 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001046 const bool trackCoverage =
1047 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001048 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001049 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001050 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001051 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001052 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1053 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001054 return;
reed61f501f2015-04-29 08:34:00 -07001055 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001056 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001057 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058
Mike Reedb43a3e02017-02-11 10:18:58 -05001059 // only have a "next" if this new layer doesn't affect the clip (rare)
1060 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001061 fMCRec->fLayer = layer;
1062 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001063
Mike Reedc61abee2017-02-28 17:45:27 -05001064 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001065 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001066 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001067 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001068
Mike Reedc42a1cd2017-02-14 14:25:14 -05001069 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1070
1071 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1072 if (layer->fNext) {
1073 // need to punch a hole in the previous device, so we don't draw there, given that
1074 // the new top-layer will allow drawing to happen "below" it.
1075 SkRegion hole(ir);
1076 do {
1077 layer = layer->fNext;
1078 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1079 } while (layer->fNext);
1080 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081}
1082
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001083int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001084 if (0xFF == alpha) {
1085 return this->saveLayer(bounds, nullptr);
1086 } else {
1087 SkPaint tmpPaint;
1088 tmpPaint.setAlpha(alpha);
1089 return this->saveLayer(bounds, &tmpPaint);
1090 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001091}
1092
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093void SkCanvas::internalRestore() {
1094 SkASSERT(fMCStack.count() != 0);
1095
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001096 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097 DeviceCM* layer = fMCRec->fLayer; // may be null
1098 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001099 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100
1101 // now do the normal restore()
1102 fMCRec->~MCRec(); // balanced in save()
1103 fMCStack.pop_back();
1104 fMCRec = (MCRec*)fMCStack.back();
1105
Mike Reedc42a1cd2017-02-14 14:25:14 -05001106 if (fMCRec) {
1107 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1108 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001109
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1111 since if we're being recorded, we don't want to record this (the
1112 recorder will have already recorded the restore).
1113 */
bsalomon49f085d2014-09-05 13:34:00 -07001114 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001115 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001116 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001117 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001118 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001119 layer->fPaint.get(),
1120 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001121 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001122 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001123 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001124 delete layer;
reedb679ca82015-04-07 04:40:48 -07001125 } else {
1126 // we're at the root
reeda499f902015-05-01 09:34:31 -07001127 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001128 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001129 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001130 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001131 }
msarettfbfa2582016-08-12 08:29:08 -07001132
1133 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001134 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001135 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1136 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137}
1138
reede8f30622016-03-23 18:59:25 -07001139sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001140 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001141 props = &fProps;
1142 }
1143 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001144}
1145
reede8f30622016-03-23 18:59:25 -07001146sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001147 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001148 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001149}
1150
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001151SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001152 return this->onImageInfo();
1153}
1154
1155SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001156 SkBaseDevice* dev = this->getDevice();
1157 if (dev) {
1158 return dev->imageInfo();
1159 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001160 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001161 }
1162}
1163
brianosman898235c2016-04-06 07:38:23 -07001164bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001165 return this->onGetProps(props);
1166}
1167
1168bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001169 SkBaseDevice* dev = this->getDevice();
1170 if (dev) {
1171 if (props) {
1172 *props = fProps;
1173 }
1174 return true;
1175 } else {
1176 return false;
1177 }
1178}
1179
reed6ceeebd2016-03-09 14:26:26 -08001180bool SkCanvas::peekPixels(SkPixmap* pmap) {
1181 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001182}
1183
reed884e97c2015-05-26 11:31:54 -07001184bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001185 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001186 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001187}
1188
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001189void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001190 SkPixmap pmap;
1191 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001192 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001193 }
1194 if (info) {
1195 *info = pmap.info();
1196 }
1197 if (rowBytes) {
1198 *rowBytes = pmap.rowBytes();
1199 }
1200 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001201 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001202 }
reed884e97c2015-05-26 11:31:54 -07001203 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001204}
1205
reed884e97c2015-05-26 11:31:54 -07001206bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001207 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001208 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001209}
1210
reed@android.com8a1c16f2008-12-17 15:59:43 +00001211/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212
Florin Malita53f77bd2017-04-28 13:48:37 -04001213void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1214 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001216 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217 paint = &tmp;
1218 }
reed@google.com4b226022011-01-11 18:32:13 +00001219
Ben Wagner2c312c42018-06-27 14:46:46 -04001220 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001221
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001223 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001224 paint = &looper.paint();
1225 SkImageFilter* filter = paint->getImageFilter();
1226 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001227 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001228 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1229 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001230 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1231 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001232 }
reed@google.com76dd2772012-01-05 21:15:07 +00001233 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001234 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001235 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236 }
reeda2217ef2016-07-20 06:04:34 -07001237
reed@google.com4e2b3d32011-04-07 14:18:59 +00001238 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239}
1240
reed32704672015-12-16 08:27:10 -08001241/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001242
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001243void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001244 if (dx || dy) {
1245 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001246 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001247
reedfe69b502016-09-12 06:31:48 -07001248 // Translate shouldn't affect the is-scale-translateness of the matrix.
1249 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001250
Mike Reedc42a1cd2017-02-14 14:25:14 -05001251 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001252
reedfe69b502016-09-12 06:31:48 -07001253 this->didTranslate(dx,dy);
1254 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255}
1256
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001257void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001258 SkMatrix m;
1259 m.setScale(sx, sy);
1260 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001261}
1262
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001263void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001264 SkMatrix m;
1265 m.setRotate(degrees);
1266 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001267}
1268
bungeman7438bfc2016-07-12 15:01:19 -07001269void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1270 SkMatrix m;
1271 m.setRotate(degrees, px, py);
1272 this->concat(m);
1273}
1274
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001275void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001276 SkMatrix m;
1277 m.setSkew(sx, sy);
1278 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001279}
1280
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001281void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001282 if (matrix.isIdentity()) {
1283 return;
1284 }
1285
reed2ff1fce2014-12-11 07:07:37 -08001286 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001287 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001288 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001289
Mike Reed7627fa52017-02-08 10:07:53 -05001290 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001291
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001292 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001293}
1294
reed8c30a812016-04-20 16:36:51 -07001295void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001296 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001297 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001298
Mike Reedc42a1cd2017-02-14 14:25:14 -05001299 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001300}
1301
1302void SkCanvas::setMatrix(const SkMatrix& matrix) {
1303 this->checkForDeferredSave();
1304 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001305 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306}
1307
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001309 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310}
1311
1312//////////////////////////////////////////////////////////////////////////////
1313
Mike Reedc1f77742016-12-09 09:00:50 -05001314void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001315 if (!rect.isFinite()) {
1316 return;
1317 }
reed2ff1fce2014-12-11 07:07:37 -08001318 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001319 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1320 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001321}
1322
Mike Reedc1f77742016-12-09 09:00:50 -05001323void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001324 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001325
Mike Reed7627fa52017-02-08 10:07:53 -05001326 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001327
reedc64eff52015-11-21 12:39:45 -08001328 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001329 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1330 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001331 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332}
1333
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001334void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1335 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001336 if (fClipRestrictionRect.isEmpty()) {
1337 // we notify the device, but we *dont* resolve deferred saves (since we're just
1338 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001339 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001340 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001341 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001342 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001343 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001344 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001345 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1346 }
1347}
1348
Mike Reedc1f77742016-12-09 09:00:50 -05001349void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001350 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001351 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001352 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001353 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1354 } else {
1355 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001356 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001357}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001358
Mike Reedc1f77742016-12-09 09:00:50 -05001359void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001360 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001361
Brian Salomona3b45d42016-10-03 11:36:16 -04001362 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001363
Mike Reed7627fa52017-02-08 10:07:53 -05001364 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001365
Mike Reed20800c82017-11-15 16:09:04 -05001366 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1367 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001368 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001369}
1370
Mike Reedc1f77742016-12-09 09:00:50 -05001371void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001372 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001373 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001374
1375 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1376 SkRect r;
1377 if (path.isRect(&r)) {
1378 this->onClipRect(r, op, edgeStyle);
1379 return;
1380 }
1381 SkRRect rrect;
1382 if (path.isOval(&r)) {
1383 rrect.setOval(r);
1384 this->onClipRRect(rrect, op, edgeStyle);
1385 return;
1386 }
1387 if (path.isRRect(&rrect)) {
1388 this->onClipRRect(rrect, op, edgeStyle);
1389 return;
1390 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001391 }
robertphillips39f05382015-11-24 09:30:12 -08001392
1393 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001394}
1395
Mike Reedc1f77742016-12-09 09:00:50 -05001396void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001397 AutoValidateClip avc(this);
1398
Brian Salomona3b45d42016-10-03 11:36:16 -04001399 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001400
Mike Reed7627fa52017-02-08 10:07:53 -05001401 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402
Brian Salomona3b45d42016-10-03 11:36:16 -04001403 const SkPath* rasterClipPath = &path;
1404 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001405 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1406 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001407 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408}
1409
Mike Reedc1f77742016-12-09 09:00:50 -05001410void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001411 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001412 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001413}
1414
Mike Reedc1f77742016-12-09 09:00:50 -05001415void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001416 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001417
reed@google.com5c3d1472011-02-22 19:12:23 +00001418 AutoValidateClip avc(this);
1419
Mike Reed20800c82017-11-15 16:09:04 -05001420 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001421 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422}
1423
reed@google.com819c9212011-02-23 18:56:55 +00001424#ifdef SK_DEBUG
1425void SkCanvas::validateClip() const {
1426 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001427 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001428 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001429 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001430 return;
1431 }
reed@google.com819c9212011-02-23 18:56:55 +00001432}
1433#endif
1434
Mike Reeda1361362017-03-07 09:37:29 -05001435bool SkCanvas::androidFramework_isClipAA() const {
1436 bool containsAA = false;
1437
1438 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1439
1440 return containsAA;
1441}
1442
1443class RgnAccumulator {
1444 SkRegion* fRgn;
1445public:
1446 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1447 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1448 SkIPoint origin = device->getOrigin();
1449 if (origin.x() | origin.y()) {
1450 rgn->translate(origin.x(), origin.y());
1451 }
1452 fRgn->op(*rgn, SkRegion::kUnion_Op);
1453 }
1454};
1455
1456void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1457 RgnAccumulator accum(rgn);
1458 SkRegion tmp;
1459
1460 rgn->setEmpty();
1461 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001462}
1463
reed@google.com5c3d1472011-02-22 19:12:23 +00001464///////////////////////////////////////////////////////////////////////////////
1465
reed@google.com754de5f2014-02-24 19:38:20 +00001466bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001467 return fMCRec->fRasterClip.isEmpty();
1468
1469 // TODO: should we only use the conservative answer in a recording canvas?
1470#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001471 SkBaseDevice* dev = this->getTopDevice();
1472 // if no device we return true
1473 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001474#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001475}
1476
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001477bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001478 SkBaseDevice* dev = this->getTopDevice();
1479 // if no device we return false
1480 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001481}
1482
msarettfbfa2582016-08-12 08:29:08 -07001483static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1484#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1485 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1486 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1487 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1488 return 0xF != _mm_movemask_ps(mask);
1489#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1490 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1491 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1492 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1493 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1494#else
1495 SkRect devRectAsRect;
1496 SkRect devClipAsRect;
1497 devRect.store(&devRectAsRect.fLeft);
1498 devClip.store(&devClipAsRect.fLeft);
1499 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1500#endif
1501}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001502
msarettfbfa2582016-08-12 08:29:08 -07001503// It's important for this function to not be inlined. Otherwise the compiler will share code
1504// between the fast path and the slow path, resulting in two slow paths.
1505static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1506 const SkMatrix& matrix) {
1507 SkRect deviceRect;
1508 matrix.mapRect(&deviceRect, src);
1509 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1510}
1511
1512bool SkCanvas::quickReject(const SkRect& src) const {
1513#ifdef SK_DEBUG
1514 // Verify that fDeviceClipBounds are set properly.
1515 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001516 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001517 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001518 } else {
msarettfbfa2582016-08-12 08:29:08 -07001519 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001520 }
msarettfbfa2582016-08-12 08:29:08 -07001521
msarett9637ea92016-08-18 14:03:30 -07001522 // Verify that fIsScaleTranslate is set properly.
1523 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001524#endif
1525
msarett9637ea92016-08-18 14:03:30 -07001526 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001527 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1528 }
1529
1530 // We inline the implementation of mapScaleTranslate() for the fast path.
1531 float sx = fMCRec->fMatrix.getScaleX();
1532 float sy = fMCRec->fMatrix.getScaleY();
1533 float tx = fMCRec->fMatrix.getTranslateX();
1534 float ty = fMCRec->fMatrix.getTranslateY();
1535 Sk4f scale(sx, sy, sx, sy);
1536 Sk4f trans(tx, ty, tx, ty);
1537
1538 // Apply matrix.
1539 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1540
1541 // Make sure left < right, top < bottom.
1542 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1543 Sk4f min = Sk4f::Min(ltrb, rblt);
1544 Sk4f max = Sk4f::Max(ltrb, rblt);
1545 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1546 // ARM this sequence generates the fastest (a single instruction).
1547 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1548
1549 // Check if the device rect is NaN or outside the clip.
1550 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001551}
1552
reed@google.com3b3e8952012-08-16 20:53:31 +00001553bool SkCanvas::quickReject(const SkPath& path) const {
1554 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001555}
1556
Mike Klein83c8dd92017-11-28 17:08:45 -05001557SkRect SkCanvas::getLocalClipBounds() const {
1558 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001559 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001560 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001561 }
1562
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001563 SkMatrix inverse;
1564 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001565 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001566 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001567 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001568
Mike Reed42e8c532017-01-23 14:09:13 -05001569 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001570 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001571 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001572
Mike Reedb57b9312018-04-23 12:12:54 -04001573 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001574 inverse.mapRect(&bounds, r);
1575 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001576}
1577
Mike Klein83c8dd92017-11-28 17:08:45 -05001578SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001579 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001580}
1581
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001583 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001584}
1585
Brian Osman11052242016-10-27 14:47:55 -04001586GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001587 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001588 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001589}
1590
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001591GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001592 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001593 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001594}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001595
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001596void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1597 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001598 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001599 if (outer.isEmpty()) {
1600 return;
1601 }
1602 if (inner.isEmpty()) {
1603 this->drawRRect(outer, paint);
1604 return;
1605 }
1606
1607 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001608 // be able to return ...
1609 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001610 //
1611 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001612 if (!outer.getBounds().contains(inner.getBounds())) {
1613 return;
1614 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001615
1616 this->onDrawDRRect(outer, inner, paint);
1617}
1618
reed41af9662015-01-05 07:49:08 -08001619void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001620 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001621 this->onDrawPaint(paint);
1622}
1623
1624void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001625 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001626 // To avoid redundant logic in our culling code and various backends, we always sort rects
1627 // before passing them along.
1628 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001629}
1630
msarettdca352e2016-08-26 06:37:45 -07001631void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001632 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001633 if (region.isEmpty()) {
1634 return;
1635 }
1636
1637 if (region.isRect()) {
1638 return this->drawIRect(region.getBounds(), paint);
1639 }
1640
1641 this->onDrawRegion(region, paint);
1642}
1643
reed41af9662015-01-05 07:49:08 -08001644void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001645 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001646 // To avoid redundant logic in our culling code and various backends, we always sort rects
1647 // before passing them along.
1648 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001649}
1650
1651void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001652 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001653 this->onDrawRRect(rrect, paint);
1654}
1655
1656void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001657 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001658 this->onDrawPoints(mode, count, pts, paint);
1659}
1660
Mike Reede88a1cb2017-03-17 09:50:46 -04001661void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1662 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001663 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001664 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001665 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1666 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001667 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001668}
1669
1670void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001671 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001672 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001673 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1674}
1675
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001676void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1677 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001678 TRACE_EVENT0("skia", TRACE_FUNC);
1679 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001680 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001681 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1682}
1683
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001684void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1685 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001686 TRACE_EVENT0("skia", TRACE_FUNC);
1687 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001688 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001689 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001690}
1691
1692void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001693 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001694 this->onDrawPath(path, paint);
1695}
1696
reeda85d4d02015-05-06 12:56:48 -07001697void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001698 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001699 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001700 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001701}
1702
Mike Reedc4e31092018-01-30 11:15:27 -05001703// Returns true if the rect can be "filled" : non-empty and finite
1704static bool fillable(const SkRect& r) {
1705 SkScalar w = r.width();
1706 SkScalar h = r.height();
1707 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1708}
1709
reede47829b2015-08-06 10:02:53 -07001710void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1711 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001712 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001713 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001714 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001715 return;
1716 }
1717 this->onDrawImageRect(image, &src, dst, paint, constraint);
1718}
reed41af9662015-01-05 07:49:08 -08001719
reed84984ef2015-07-17 07:09:43 -07001720void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1721 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001722 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001723 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001724}
1725
reede47829b2015-08-06 10:02:53 -07001726void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1727 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001728 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001729 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1730 constraint);
1731}
reede47829b2015-08-06 10:02:53 -07001732
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001733namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001734class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001735public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001736 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1737 if (!origPaint) {
1738 return;
1739 }
1740 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1741 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1742 }
1743 if (origPaint->getMaskFilter()) {
1744 fPaint.writable()->setMaskFilter(nullptr);
1745 }
1746 if (origPaint->isAntiAlias()) {
1747 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001748 }
1749 }
1750
1751 const SkPaint* get() const {
1752 return fPaint;
1753 }
1754
1755private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001756 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001757};
1758} // namespace
1759
reed4c21dc52015-06-25 12:32:03 -07001760void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1761 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001762 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001763 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001764 if (dst.isEmpty()) {
1765 return;
1766 }
msarett552bca92016-08-03 06:53:26 -07001767 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001768 LatticePaint latticePaint(paint);
1769 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001770 } else {
reede47829b2015-08-06 10:02:53 -07001771 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001772 }
reed4c21dc52015-06-25 12:32:03 -07001773}
1774
msarett16882062016-08-16 09:31:08 -07001775void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1776 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001777 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001778 RETURN_ON_NULL(image);
1779 if (dst.isEmpty()) {
1780 return;
1781 }
msarett71df2d72016-09-30 12:41:42 -07001782
1783 SkIRect bounds;
1784 Lattice latticePlusBounds = lattice;
1785 if (!latticePlusBounds.fBounds) {
1786 bounds = SkIRect::MakeWH(image->width(), image->height());
1787 latticePlusBounds.fBounds = &bounds;
1788 }
1789
1790 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001791 LatticePaint latticePaint(paint);
1792 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001793 } else {
1794 this->drawImageRect(image, dst, paint);
1795 }
1796}
1797
Brian Salomond7065e72018-10-12 11:42:02 -04001798void SkCanvas::experimental_DrawImageSetV0(const ImageSetEntry imageSet[], int cnt, float alpha,
1799 SkFilterQuality filterQuality, SkBlendMode mode) {
1800 TRACE_EVENT0("skia", TRACE_FUNC);
1801 RETURN_ON_NULL(imageSet);
1802 RETURN_ON_FALSE(cnt);
1803
1804 this->onDrawImageSet(imageSet, cnt, alpha, filterQuality, mode);
1805}
1806
reed41af9662015-01-05 07:49:08 -08001807void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001808 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001809 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001810 return;
1811 }
reed41af9662015-01-05 07:49:08 -08001812 this->onDrawBitmap(bitmap, dx, dy, paint);
1813}
1814
reede47829b2015-08-06 10:02:53 -07001815void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001816 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001817 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001818 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001819 return;
1820 }
reede47829b2015-08-06 10:02:53 -07001821 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001822}
1823
reed84984ef2015-07-17 07:09:43 -07001824void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1825 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001826 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001827}
1828
reede47829b2015-08-06 10:02:53 -07001829void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1830 SrcRectConstraint constraint) {
1831 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1832 constraint);
1833}
reede47829b2015-08-06 10:02:53 -07001834
reed41af9662015-01-05 07:49:08 -08001835void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1836 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001837 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001838 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001839 return;
1840 }
msarett552bca92016-08-03 06:53:26 -07001841 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001842 LatticePaint latticePaint(paint);
1843 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001844 } else {
reeda5517e22015-07-14 10:54:12 -07001845 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001846 }
reed41af9662015-01-05 07:49:08 -08001847}
1848
msarettc573a402016-08-02 08:05:56 -07001849void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1850 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001851 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001852 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001853 return;
1854 }
msarett71df2d72016-09-30 12:41:42 -07001855
1856 SkIRect bounds;
1857 Lattice latticePlusBounds = lattice;
1858 if (!latticePlusBounds.fBounds) {
1859 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1860 latticePlusBounds.fBounds = &bounds;
1861 }
1862
1863 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001864 LatticePaint latticePaint(paint);
1865 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001866 } else {
msarett16882062016-08-16 09:31:08 -07001867 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001868 }
msarettc573a402016-08-02 08:05:56 -07001869}
1870
reed71c3c762015-06-24 10:29:17 -07001871void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001872 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001873 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001874 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001875 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001876 if (count <= 0) {
1877 return;
1878 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001879 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001880 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001881 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001882}
1883
reedf70b5312016-03-04 16:36:20 -08001884void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001885 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001886 if (key) {
1887 this->onDrawAnnotation(rect, key, value);
1888 }
1889}
1890
reede47829b2015-08-06 10:02:53 -07001891void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1892 const SkPaint* paint, SrcRectConstraint constraint) {
1893 if (src) {
1894 this->drawImageRect(image, *src, dst, paint, constraint);
1895 } else {
1896 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1897 dst, paint, constraint);
1898 }
1899}
1900void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1901 const SkPaint* paint, SrcRectConstraint constraint) {
1902 if (src) {
1903 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1904 } else {
1905 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1906 dst, paint, constraint);
1907 }
1908}
1909
Mike Reed4204da22017-05-17 08:53:36 -04001910void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001911 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001912 this->onDrawShadowRec(path, rec);
1913}
1914
1915void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1916 SkPaint paint;
1917 const SkRect& pathBounds = path.getBounds();
1918
Ben Wagner2c312c42018-06-27 14:46:46 -04001919 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001920 while (iter.next()) {
1921 iter.fDevice->drawShadow(path, rec);
1922 }
1923 LOOPER_END
1924}
1925
reed@android.com8a1c16f2008-12-17 15:59:43 +00001926//////////////////////////////////////////////////////////////////////////////
1927// These are the virtual drawing methods
1928//////////////////////////////////////////////////////////////////////////////
1929
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001930void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001931 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001932 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1933 }
1934}
1935
reed41af9662015-01-05 07:49:08 -08001936void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001937 this->internalDrawPaint(paint);
1938}
1939
1940void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001941 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001942
1943 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001944 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001945 }
1946
reed@google.com4e2b3d32011-04-07 14:18:59 +00001947 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001948}
1949
reed41af9662015-01-05 07:49:08 -08001950void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1951 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001952 if ((long)count <= 0) {
1953 return;
1954 }
1955
Mike Reed822128b2017-02-28 16:41:03 -05001956 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001957 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001958 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001959 // special-case 2 points (common for drawing a single line)
1960 if (2 == count) {
1961 r.set(pts[0], pts[1]);
1962 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001963 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001964 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001965 if (!r.isFinite()) {
1966 return;
1967 }
Mike Reed822128b2017-02-28 16:41:03 -05001968 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001969 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1970 return;
1971 }
1972 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001973 }
reed@google.coma584aed2012-05-16 14:06:02 +00001974
halcanary96fcdcc2015-08-27 07:41:13 -07001975 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001976
Ben Wagner2c312c42018-06-27 14:46:46 -04001977 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001978
reed@android.com8a1c16f2008-12-17 15:59:43 +00001979 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001980 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001981 }
reed@google.com4b226022011-01-11 18:32:13 +00001982
reed@google.com4e2b3d32011-04-07 14:18:59 +00001983 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001984}
1985
reed4a167172016-08-18 17:15:25 -07001986static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1987 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07001988 (intptr_t)paint.getLooper() ) != 0;
1989}
1990
reed41af9662015-01-05 07:49:08 -08001991void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001992 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001993 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001994 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001995 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001996 return;
1997 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998 }
reed@google.com4b226022011-01-11 18:32:13 +00001999
reed4a167172016-08-18 17:15:25 -07002000 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002001 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002002
reed4a167172016-08-18 17:15:25 -07002003 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002004 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002005 }
2006
2007 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002008 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002009 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002010 SkDrawIter iter(this);
2011 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002012 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002013 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002014 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002015}
2016
msarett44df6512016-08-25 13:54:30 -07002017void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002018 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002019 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002020 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002021 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2022 return;
2023 }
msarett44df6512016-08-25 13:54:30 -07002024 }
2025
Ben Wagner2c312c42018-06-27 14:46:46 -04002026 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002027
2028 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002029 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002030 }
2031
2032 LOOPER_END
2033}
2034
reed41af9662015-01-05 07:49:08 -08002035void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002036 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002037 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002038 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002039 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002040 return;
2041 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002042 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002043
Ben Wagner2c312c42018-06-27 14:46:46 -04002044 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002045
2046 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002047 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002048 }
2049
2050 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002051}
2052
bsalomonac3aa242016-08-19 11:25:19 -07002053void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2054 SkScalar sweepAngle, bool useCenter,
2055 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002056 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002057 if (paint.canComputeFastBounds()) {
2058 SkRect storage;
2059 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002060 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002061 return;
2062 }
bsalomonac3aa242016-08-19 11:25:19 -07002063 }
2064
Ben Wagner2c312c42018-06-27 14:46:46 -04002065 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002066
2067 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002068 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002069 }
2070
2071 LOOPER_END
2072}
2073
reed41af9662015-01-05 07:49:08 -08002074void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002075 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002076 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002077 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2078 return;
2079 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002080 }
2081
2082 if (rrect.isRect()) {
2083 // call the non-virtual version
2084 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002085 return;
2086 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002087 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002088 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2089 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002090 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002091
Ben Wagner2c312c42018-06-27 14:46:46 -04002092 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002093
2094 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002095 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002096 }
2097
2098 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002099}
2100
Mike Reed822128b2017-02-28 16:41:03 -05002101void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002102 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002103 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002104 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2105 return;
2106 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002107 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002108
Ben Wagner2c312c42018-06-27 14:46:46 -04002109 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002110
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002111 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002112 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002113 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002114
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002115 LOOPER_END
2116}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002117
reed41af9662015-01-05 07:49:08 -08002118void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002119 if (!path.isFinite()) {
2120 return;
2121 }
2122
Mike Reed822128b2017-02-28 16:41:03 -05002123 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002124 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002125 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002126 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2127 return;
2128 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002129 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002130
Mike Reed822128b2017-02-28 16:41:03 -05002131 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002132 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002133 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002134 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002135 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002136 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002137
Ben Wagner2c312c42018-06-27 14:46:46 -04002138 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002139
2140 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002141 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002142 }
2143
reed@google.com4e2b3d32011-04-07 14:18:59 +00002144 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145}
2146
reed262a71b2015-12-05 13:07:27 -08002147bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002148 if (!paint.getImageFilter()) {
2149 return false;
2150 }
2151
2152 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002153 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002154 return false;
2155 }
2156
2157 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2158 // Once we can filter and the filter will return a result larger than itself, we should be
2159 // able to remove this constraint.
2160 // skbug.com/4526
2161 //
2162 SkPoint pt;
2163 ctm.mapXY(x, y, &pt);
2164 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2165 return ir.contains(fMCRec->fRasterClip.getBounds());
2166}
2167
Mike Reedf441cfc2018-04-11 14:50:16 -04002168// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2169// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2170// null.
2171static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2172 if (paintParam) {
2173 *real = *paintParam;
2174 real->setStyle(SkPaint::kFill_Style);
2175 real->setPathEffect(nullptr);
2176 paintParam = real;
2177 }
2178 return paintParam;
2179}
2180
reeda85d4d02015-05-06 12:56:48 -07002181void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002182 SkPaint realPaint;
2183 paint = init_image_paint(&realPaint, paint);
2184
reeda85d4d02015-05-06 12:56:48 -07002185 SkRect bounds = SkRect::MakeXYWH(x, y,
2186 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002187 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002188 SkRect tmp = bounds;
2189 if (paint) {
2190 paint->computeFastBounds(tmp, &tmp);
2191 }
2192 if (this->quickReject(tmp)) {
2193 return;
2194 }
reeda85d4d02015-05-06 12:56:48 -07002195 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002196 // At this point we need a real paint object. If the caller passed null, then we should
2197 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2198 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2199 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002200
reeda2217ef2016-07-20 06:04:34 -07002201 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002202 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2203 *paint);
2204 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002205 special = this->getDevice()->makeSpecial(image);
2206 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002207 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002208 }
2209 }
2210
reed262a71b2015-12-05 13:07:27 -08002211 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2212
reeda85d4d02015-05-06 12:56:48 -07002213 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002214 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002215 if (special) {
2216 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002217 iter.fDevice->ctm().mapXY(x, y, &pt);
2218 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002219 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002220 SkScalarRoundToInt(pt.fY), pnt,
2221 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002222 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002223 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002224 }
reeda85d4d02015-05-06 12:56:48 -07002225 }
halcanary9d524f22016-03-29 09:03:52 -07002226
reeda85d4d02015-05-06 12:56:48 -07002227 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002228}
2229
reed41af9662015-01-05 07:49:08 -08002230void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002231 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002232 SkPaint realPaint;
2233 paint = init_image_paint(&realPaint, paint);
2234
halcanary96fcdcc2015-08-27 07:41:13 -07002235 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002236 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002237 if (paint) {
2238 paint->computeFastBounds(dst, &storage);
2239 }
2240 if (this->quickReject(storage)) {
2241 return;
2242 }
reeda85d4d02015-05-06 12:56:48 -07002243 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002244 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002245
Ben Wagner2c312c42018-06-27 14:46:46 -04002246 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002247
reeda85d4d02015-05-06 12:56:48 -07002248 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002249 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002250 }
halcanary9d524f22016-03-29 09:03:52 -07002251
reeda85d4d02015-05-06 12:56:48 -07002252 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002253}
2254
reed41af9662015-01-05 07:49:08 -08002255void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002256 SkDEBUGCODE(bitmap.validate();)
2257
reed33366972015-10-08 09:22:02 -07002258 if (bitmap.drawsNothing()) {
2259 return;
2260 }
2261
Mike Reedf441cfc2018-04-11 14:50:16 -04002262 SkPaint realPaint;
2263 init_image_paint(&realPaint, paint);
2264 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002265
Mike Reed822128b2017-02-28 16:41:03 -05002266 SkRect bounds;
2267 bitmap.getBounds(&bounds);
2268 bounds.offset(x, y);
2269 bool canFastBounds = paint->canComputeFastBounds();
2270 if (canFastBounds) {
2271 SkRect storage;
2272 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002273 return;
2274 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002275 }
reed@google.com4b226022011-01-11 18:32:13 +00002276
reeda2217ef2016-07-20 06:04:34 -07002277 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002278 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2279 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002280 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002281 special = this->getDevice()->makeSpecial(bitmap);
2282 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002283 drawAsSprite = false;
2284 }
2285 }
2286
Mike Reed822128b2017-02-28 16:41:03 -05002287 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002288
2289 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002290 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002291 if (special) {
reed262a71b2015-12-05 13:07:27 -08002292 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002293 iter.fDevice->ctm().mapXY(x, y, &pt);
2294 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002295 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002296 SkScalarRoundToInt(pt.fY), pnt,
2297 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002298 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002299 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002300 }
reed33366972015-10-08 09:22:02 -07002301 }
msarettfbfa2582016-08-12 08:29:08 -07002302
reed33366972015-10-08 09:22:02 -07002303 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002304}
2305
reed@google.com9987ec32011-09-07 11:57:52 +00002306// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002307void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002308 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002309 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002310 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002311 return;
2312 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002313
halcanary96fcdcc2015-08-27 07:41:13 -07002314 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002315 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002316 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2317 return;
2318 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002319 }
reed@google.com3d608122011-11-21 15:16:16 +00002320
reed@google.com33535f32012-09-25 15:37:50 +00002321 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002322 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002323 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002325
Ben Wagner2c312c42018-06-27 14:46:46 -04002326 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002327
reed@google.com33535f32012-09-25 15:37:50 +00002328 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002329 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002330 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002331
reed@google.com33535f32012-09-25 15:37:50 +00002332 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002333}
2334
reed41af9662015-01-05 07:49:08 -08002335void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002336 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002337 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002338 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002339}
2340
reed4c21dc52015-06-25 12:32:03 -07002341void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2342 const SkPaint* paint) {
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;
senorblanco87e066e2015-10-28 11:23:36 -07002348 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2349 return;
2350 }
reed@google.com3d608122011-11-21 15:16:16 +00002351 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002352 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002353
Ben Wagner2c312c42018-06-27 14:46:46 -04002354 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002355
reed4c21dc52015-06-25 12:32:03 -07002356 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002357 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002358 }
halcanary9d524f22016-03-29 09:03:52 -07002359
reed4c21dc52015-06-25 12:32:03 -07002360 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002361}
2362
reed41af9662015-01-05 07:49:08 -08002363void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2364 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002365 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002366 SkPaint realPaint;
2367 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002368
halcanary96fcdcc2015-08-27 07:41:13 -07002369 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002370 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002371 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2372 return;
2373 }
reed4c21dc52015-06-25 12:32:03 -07002374 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002375 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002376
Ben Wagner2c312c42018-06-27 14:46:46 -04002377 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002378
reed4c21dc52015-06-25 12:32:03 -07002379 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002380 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002381 }
halcanary9d524f22016-03-29 09:03:52 -07002382
reed4c21dc52015-06-25 12:32:03 -07002383 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002384}
2385
msarett16882062016-08-16 09:31:08 -07002386void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2387 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002388 SkPaint realPaint;
2389 paint = init_image_paint(&realPaint, paint);
2390
msarett16882062016-08-16 09:31:08 -07002391 if (nullptr == paint || paint->canComputeFastBounds()) {
2392 SkRect storage;
2393 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2394 return;
2395 }
2396 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002397 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002398
Ben Wagner2c312c42018-06-27 14:46:46 -04002399 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002400
2401 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002402 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002403 }
2404
2405 LOOPER_END
2406}
2407
Brian Salomond7065e72018-10-12 11:42:02 -04002408void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count, float alpha,
2409 SkFilterQuality filterQuality, SkBlendMode mode) {
2410 SkPaint paint;
2411 LOOPER_BEGIN(paint, nullptr);
2412 while (iter.next()) {
2413 iter.fDevice->drawImageSet(imageSet, count, alpha, filterQuality, mode);
2414 }
2415 LOOPER_END
2416}
2417
msarett16882062016-08-16 09:31:08 -07002418void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2419 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002420 SkPaint realPaint;
2421 paint = init_image_paint(&realPaint, paint);
2422
msarett16882062016-08-16 09:31:08 -07002423 if (nullptr == paint || paint->canComputeFastBounds()) {
2424 SkRect storage;
2425 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2426 return;
2427 }
2428 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002429 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002430
Ben Wagner2c312c42018-06-27 14:46:46 -04002431 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002432
2433 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002434 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002435 }
2436
2437 LOOPER_END
2438}
2439
reed@google.come0d9ce82014-04-23 04:00:17 +00002440void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2441 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002442
Ben Wagner2c312c42018-06-27 14:46:46 -04002443 LOOPER_BEGIN(paint, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002444
2445 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002446 fScratchGlyphRunBuilder->drawText(
Herb Derby4a447432018-06-22 11:45:27 -04002447 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Herb Derby8a6348e2018-07-12 15:30:35 -04002448 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002449 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002450 }
2451
reed@google.com4e2b3d32011-04-07 14:18:59 +00002452 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002453}
2454
reed@google.come0d9ce82014-04-23 04:00:17 +00002455void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2456 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002457
Ben Wagner2c312c42018-06-27 14:46:46 -04002458 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002459
reed@android.com8a1c16f2008-12-17 15:59:43 +00002460 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002461 fScratchGlyphRunBuilder->drawPosText(looper.paint(), text, byteLength, pos);
Herb Derby8a6348e2018-07-12 15:30:35 -04002462 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002463 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002464 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002465
reed@google.com4e2b3d32011-04-07 14:18:59 +00002466 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002467}
2468
reed@google.come0d9ce82014-04-23 04:00:17 +00002469void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2470 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002471
Ben Wagner2c312c42018-06-27 14:46:46 -04002472 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002473
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002475 fScratchGlyphRunBuilder->drawPosTextH(
Herb Derby4a447432018-06-22 11:45:27 -04002476 looper.paint(), text, byteLength, xpos, constY);
Herb Derby8a6348e2018-07-12 15:30:35 -04002477 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002478 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002479 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002480
reed@google.com4e2b3d32011-04-07 14:18:59 +00002481 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482}
2483
Herb Derby2eacff02018-07-18 13:41:15 -04002484void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[],
reed45561a02016-07-07 12:47:17 -07002485 const SkRect* cullRect, const SkPaint& paint) {
2486 if (cullRect && this->quickReject(*cullRect)) {
2487 return;
2488 }
2489
Ben Wagner2c312c42018-06-27 14:46:46 -04002490 LOOPER_BEGIN(paint, nullptr)
reed45561a02016-07-07 12:47:17 -07002491
2492 while (iter.next()) {
Herb Derby2eacff02018-07-18 13:41:15 -04002493 fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len);
2494 auto list = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb935cf82018-07-26 16:54:18 -04002495 if (!list.empty()) {
2496 auto glyphRun = list[0];
Herb Derby2eacff02018-07-18 13:41:15 -04002497 iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform);
2498 }
reed45561a02016-07-07 12:47:17 -07002499 }
2500
2501 LOOPER_END
2502}
2503
fmalita00d5c2c2014-08-21 08:53:26 -07002504void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2505 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002506 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002507 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002508 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002509 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002510 SkRect tmp;
2511 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2512 return;
2513 }
2514 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002515 }
2516
fmalita024f9962015-03-03 19:08:17 -08002517 // We cannot filter in the looper as we normally do, because the paint is
2518 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002519 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002520
fmalitaaa1b9122014-08-28 14:32:24 -07002521 while (iter.next()) {
Herb Derbyb983e6b2018-07-13 13:26:29 -04002522 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, SkPoint::Make(x, y));
2523 iter.fDevice->drawGlyphRunList(fScratchGlyphRunBuilder->useGlyphRunList());
fmalita00d5c2c2014-08-21 08:53:26 -07002524 }
2525
fmalitaaa1b9122014-08-28 14:32:24 -07002526 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002527}
2528
Cary Clark2a475ea2017-04-28 15:35:12 -04002529void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2530 this->drawText(string.c_str(), string.size(), x, y, paint);
2531}
2532
reed@google.come0d9ce82014-04-23 04:00:17 +00002533// These will become non-virtual, so they always call the (virtual) onDraw... method
2534void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2535 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002536 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002537 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002538 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002539 this->onDrawText(text, byteLength, x, y, paint);
2540 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002541}
2542void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2543 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002544 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002545 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002546 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002547 this->onDrawPosText(text, byteLength, pos, paint);
2548 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002549}
2550void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2551 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002552 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002553 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002554 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002555 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2556 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002557}
Mike Reed7c8d2e92018-08-27 16:38:05 -04002558
reed45561a02016-07-07 12:47:17 -07002559void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2560 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002561 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002562 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002563 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002564 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2565 }
2566}
fmalita00d5c2c2014-08-21 08:53:26 -07002567void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2568 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002569 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002570 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002571 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002572 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002573}
reed@google.come0d9ce82014-04-23 04:00:17 +00002574
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002575void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002576 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002577 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002578
2579 while (iter.next()) {
2580 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002581 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002582 }
2583
2584 LOOPER_END
2585}
2586
dandovb3c9d1c2014-08-12 08:34:29 -07002587void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002588 const SkPoint texCoords[4], SkBlendMode bmode,
2589 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002590 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002591 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002592 return;
2593 }
mtklein6cfa73a2014-08-13 13:33:49 -07002594
Mike Reedfaba3712016-11-03 14:45:31 -04002595 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002596}
2597
2598void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002599 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002600 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002601 // Since a patch is always within the convex hull of the control points, we discard it when its
2602 // bounding rectangle is completely outside the current clip.
2603 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002604 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002605 if (this->quickReject(bounds)) {
2606 return;
2607 }
mtklein6cfa73a2014-08-13 13:33:49 -07002608
Ben Wagner2c312c42018-06-27 14:46:46 -04002609 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002610
dandovecfff212014-08-04 10:02:00 -07002611 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002612 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002613 }
mtklein6cfa73a2014-08-13 13:33:49 -07002614
dandovecfff212014-08-04 10:02:00 -07002615 LOOPER_END
2616}
2617
reeda8db7282015-07-07 10:22:31 -07002618void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002619#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002620 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002621#endif
reede3b38ce2016-01-08 09:18:44 -08002622 RETURN_ON_NULL(dr);
2623 if (x || y) {
2624 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2625 this->onDrawDrawable(dr, &matrix);
2626 } else {
2627 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002628 }
2629}
2630
reeda8db7282015-07-07 10:22:31 -07002631void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002632#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002633 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002634#endif
reede3b38ce2016-01-08 09:18:44 -08002635 RETURN_ON_NULL(dr);
2636 if (matrix && matrix->isIdentity()) {
2637 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002638 }
reede3b38ce2016-01-08 09:18:44 -08002639 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002640}
2641
2642void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002643 // drawable bounds are no longer reliable (e.g. android displaylist)
2644 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002645 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002646}
2647
reed71c3c762015-06-24 10:29:17 -07002648void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002649 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002650 const SkRect* cull, const SkPaint* paint) {
2651 if (cull && this->quickReject(*cull)) {
2652 return;
2653 }
2654
2655 SkPaint pnt;
2656 if (paint) {
2657 pnt = *paint;
2658 }
halcanary9d524f22016-03-29 09:03:52 -07002659
Ben Wagner2c312c42018-06-27 14:46:46 -04002660 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002661 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002662 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002663 }
2664 LOOPER_END
2665}
2666
reedf70b5312016-03-04 16:36:20 -08002667void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2668 SkASSERT(key);
2669
2670 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002671 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002672 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002673 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002674 }
2675 LOOPER_END
2676}
2677
reed@android.com8a1c16f2008-12-17 15:59:43 +00002678//////////////////////////////////////////////////////////////////////////////
2679// These methods are NOT virtual, and therefore must call back into virtual
2680// methods, rather than actually drawing themselves.
2681//////////////////////////////////////////////////////////////////////////////
2682
reed374772b2016-10-05 17:33:02 -07002683void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002684 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002685 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002686 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002687 this->drawPaint(paint);
2688}
2689
2690void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002691 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002692 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2693}
2694
Mike Reed3661bc92017-02-22 13:21:42 -05002695void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002696 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 pts[0].set(x0, y0);
2698 pts[1].set(x1, y1);
2699 this->drawPoints(kLines_PointMode, 2, pts, paint);
2700}
2701
Mike Reed3661bc92017-02-22 13:21:42 -05002702void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002703 if (radius < 0) {
2704 radius = 0;
2705 }
2706
2707 SkRect r;
2708 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002709 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002710}
2711
2712void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2713 const SkPaint& paint) {
2714 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002715 SkRRect rrect;
2716 rrect.setRectXY(r, rx, ry);
2717 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002718 } else {
2719 this->drawRect(r, paint);
2720 }
2721}
2722
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2724 SkScalar sweepAngle, bool useCenter,
2725 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002726 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002727 if (oval.isEmpty() || !sweepAngle) {
2728 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002729 }
bsalomon21af9ca2016-08-25 12:29:23 -07002730 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002731}
2732
reed@android.comf76bacf2009-05-13 14:00:33 +00002733///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002734#ifdef SK_DISABLE_SKPICTURE
2735void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002736
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002737
2738void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2739 const SkPaint* paint) {}
2740#else
Mike Klein88d90712018-01-27 17:30:04 +00002741/**
2742 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2743 * against the playback cost of recursing into the subpicture to get at its actual ops.
2744 *
2745 * For now we pick a conservatively small value, though measurement (and other heuristics like
2746 * the type of ops contained) may justify changing this value.
2747 */
2748#define kMaxPictureOpsToUnrollInsteadOfRef 1
2749
reedd5fa1a42014-08-09 11:08:05 -07002750void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002751 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002752 RETURN_ON_NULL(picture);
2753
reede3b38ce2016-01-08 09:18:44 -08002754 if (matrix && matrix->isIdentity()) {
2755 matrix = nullptr;
2756 }
Mike Klein88d90712018-01-27 17:30:04 +00002757 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2758 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2759 picture->playback(this);
2760 } else {
2761 this->onDrawPicture(picture, matrix, paint);
2762 }
reedd5fa1a42014-08-09 11:08:05 -07002763}
robertphillips9b14f262014-06-04 05:40:44 -07002764
reedd5fa1a42014-08-09 11:08:05 -07002765void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2766 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002767 if (!paint || paint->canComputeFastBounds()) {
2768 SkRect bounds = picture->cullRect();
2769 if (paint) {
2770 paint->computeFastBounds(bounds, &bounds);
2771 }
2772 if (matrix) {
2773 matrix->mapRect(&bounds);
2774 }
2775 if (this->quickReject(bounds)) {
2776 return;
2777 }
2778 }
2779
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002780 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002781 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002783#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784
reed@android.com8a1c16f2008-12-17 15:59:43 +00002785///////////////////////////////////////////////////////////////////////////////
2786///////////////////////////////////////////////////////////////////////////////
2787
reed3aafe112016-08-18 12:45:34 -07002788SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002789 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790
2791 SkASSERT(canvas);
2792
reed3aafe112016-08-18 12:45:34 -07002793 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794 fDone = !fImpl->next();
2795}
2796
2797SkCanvas::LayerIter::~LayerIter() {
2798 fImpl->~SkDrawIter();
2799}
2800
2801void SkCanvas::LayerIter::next() {
2802 fDone = !fImpl->next();
2803}
2804
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002805SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002806 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807}
2808
2809const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002810 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002811}
2812
2813const SkPaint& SkCanvas::LayerIter::paint() const {
2814 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002815 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816 paint = &fDefaultPaint;
2817 }
2818 return *paint;
2819}
2820
Mike Reedca37f322018-03-08 13:22:16 -05002821SkIRect SkCanvas::LayerIter::clipBounds() const {
2822 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002823}
2824
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2826int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002827
2828///////////////////////////////////////////////////////////////////////////////
2829
Mike Reed5df49342016-11-12 08:06:55 -06002830std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002831 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002832 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002833 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002834 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002835
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002836 SkBitmap bitmap;
2837 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002838 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002839 }
Mike Reed12f77342017-11-08 11:19:52 -05002840
2841 return props ?
2842 skstd::make_unique<SkCanvas>(bitmap, *props) :
2843 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002844}
reedd5fa1a42014-08-09 11:08:05 -07002845
2846///////////////////////////////////////////////////////////////////////////////
2847
Florin Malitaee424ac2016-12-01 12:47:59 -05002848SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002849 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002850
Florin Malita439ace92016-12-02 12:05:41 -05002851SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002852 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002853
Herb Derbyefe39bc2018-05-01 17:06:20 -04002854SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002855 : INHERITED(device) {}
2856
Florin Malitaee424ac2016-12-01 12:47:59 -05002857SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2858 (void)this->INHERITED::getSaveLayerStrategy(rec);
2859 return kNoLayer_SaveLayerStrategy;
2860}
2861
2862///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002863
reed73603f32016-09-20 08:42:38 -07002864static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2865static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2866static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2867static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2868static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2869static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002870
2871///////////////////////////////////////////////////////////////////////////////////////////////////
2872
2873SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2874 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002875 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002876 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2877 SkIPoint origin = dev->getOrigin();
2878 SkMatrix ctm = this->getTotalMatrix();
2879 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2880
2881 SkIRect clip = fMCRec->fRasterClip.getBounds();
2882 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002883 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002884 clip.setEmpty();
2885 }
2886
2887 fAllocator->updateHandle(handle, ctm, clip);
2888 return handle;
2889 }
2890 return nullptr;
2891}
2892
2893static bool install(SkBitmap* bm, const SkImageInfo& info,
2894 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002895 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002896}
2897
2898SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2899 SkBitmap* bm) {
2900 SkRasterHandleAllocator::Rec rec;
2901 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2902 return nullptr;
2903 }
2904 return rec.fHandle;
2905}
2906
2907std::unique_ptr<SkCanvas>
2908SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2909 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002910 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002911 return nullptr;
2912 }
2913
2914 SkBitmap bm;
2915 Handle hndl;
2916
2917 if (rec) {
2918 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2919 } else {
2920 hndl = alloc->allocBitmap(info, &bm);
2921 }
2922 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2923}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002924
2925///////////////////////////////////////////////////////////////////////////////////////////////////
2926
2927