blob: 59511c7113af9edd60542b4c413924b5014a6d71 [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
Mike Reed148b7fd2018-12-18 17:38:18 -0500211namespace {
212// Encapsulate state needed to restore from saveBehind()
213struct BackImage {
214 sk_sp<SkSpecialImage> fImage;
215 SkIPoint fLoc;
216};
217}
218
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219/* This is the record we keep for each save/restore level in the stack.
220 Since a level optionally copies the matrix and/or stack, we have pointers
221 for these fields. If the value is copied for this level, the copy is
222 stored in the ...Storage field, and the pointer points to that. If the
223 value is not copied for this level, we ignore ...Storage, and just point
224 at the corresponding value in the previous level in the stack.
225*/
226class SkCanvas::MCRec {
227public:
Mike Reed148b7fd2018-12-18 17:38:18 -0500228 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229 /* If there are any layers in the stack, this points to the top-most
230 one that is at or below this level in the stack (so we know what
231 bitmap/device to draw into from this level. This value is NOT
232 reference counted, since the real owner is either our fLayer field,
233 or a previous one in a lower level.)
234 */
Mike Reed148b7fd2018-12-18 17:38:18 -0500235 DeviceCM* fTopLayer;
236 std::unique_ptr<BackImage> fBackImage;
237 SkConservativeClip fRasterClip;
238 SkMatrix fMatrix;
239 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240
Mike Reeda1361362017-03-07 09:37:29 -0500241 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700242 fLayer = nullptr;
243 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800244 fMatrix.reset();
245 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700246
reedd9544982014-09-09 18:46:22 -0700247 // don't bother initializing fNext
248 inc_rec();
249 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400250 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700251 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700252 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800253 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700254
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 // don't bother initializing fNext
256 inc_rec();
257 }
258 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700259 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 dec_rec();
261 }
mtkleinfeaadee2015-04-08 11:25:48 -0700262
263 void reset(const SkIRect& bounds) {
264 SkASSERT(fLayer);
265 SkASSERT(fDeferredSaveCount == 0);
266
267 fMatrix.reset();
268 fRasterClip.setRect(bounds);
269 fLayer->reset(bounds);
270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271};
272
Mike Reeda1361362017-03-07 09:37:29 -0500273class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274public:
Mike Reeda1361362017-03-07 09:37:29 -0500275 SkDrawIter(SkCanvas* canvas)
276 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
277 {}
reed@google.com4b226022011-01-11 18:32:13 +0000278
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000280 const DeviceCM* rec = fCurrLayer;
281 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400282 fDevice = rec->fDevice.get();
283 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700285 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000286 return true;
287 }
288 return false;
289 }
reed@google.com4b226022011-01-11 18:32:13 +0000290
reed@google.com6f8f2922011-03-04 22:27:10 +0000291 int getX() const { return fDevice->getOrigin().x(); }
292 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000294
Mike Reed99330ba2017-02-22 11:01:08 -0500295 SkBaseDevice* fDevice;
296
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 const DeviceCM* fCurrLayer;
299 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300};
301
Florin Malita713b8ef2017-04-28 10:57:24 -0400302#define FOR_EACH_TOP_DEVICE( code ) \
303 do { \
304 DeviceCM* layer = fMCRec->fTopLayer; \
305 while (layer) { \
306 SkBaseDevice* device = layer->fDevice.get(); \
307 if (device) { \
308 code; \
309 } \
310 layer = layer->fNext; \
311 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500312 } while (0)
313
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314/////////////////////////////////////////////////////////////////////////////
315
reeddbc3cef2015-04-29 12:18:57 -0700316static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
317 return lazy->isValid() ? lazy->get() : lazy->set(orig);
318}
319
320/**
321 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700322 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700323 */
reedd053ce92016-03-22 10:17:23 -0700324static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700325 SkImageFilter* imgf = paint.getImageFilter();
326 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700327 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700328 }
329
reedd053ce92016-03-22 10:17:23 -0700330 SkColorFilter* imgCFPtr;
331 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700332 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700333 }
reedd053ce92016-03-22 10:17:23 -0700334 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700335
336 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700337 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700338 // there is no existing paint colorfilter, so we can just return the imagefilter's
339 return imgCF;
340 }
341
342 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
343 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500344 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700345}
346
senorblanco87e066e2015-10-28 11:23:36 -0700347/**
348 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
349 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
350 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
351 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
352 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
353 * conservative "effective" bounds based on the settings in the paint... with one exception. This
354 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
355 * deliberately ignored.
356 */
357static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
358 const SkRect& rawBounds,
359 SkRect* storage) {
360 SkPaint tmpUnfiltered(paint);
361 tmpUnfiltered.setImageFilter(nullptr);
362 if (tmpUnfiltered.canComputeFastBounds()) {
363 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
364 } else {
365 return rawBounds;
366 }
367}
368
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369class AutoDrawLooper {
370public:
senorblanco87e066e2015-10-28 11:23:36 -0700371 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
372 // paint. It's used to determine the size of the offscreen layer for filters.
373 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700374 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700375 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000376 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700377 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000378 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700379 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000380 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381
reedd053ce92016-03-22 10:17:23 -0700382 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700383 if (simplifiedCF) {
384 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700385 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700386 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700387 fPaint = paint;
388 }
389
390 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700391 /**
392 * We implement ImageFilters for a given draw by creating a layer, then applying the
393 * imagefilter to the pixels of that layer (its backing surface/image), and then
394 * we call restore() to xfer that layer to the main canvas.
395 *
396 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
397 * 2. Generate the src pixels:
398 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
399 * return (fPaint). We then draw the primitive (using srcover) into a cleared
400 * buffer/surface.
401 * 3. Restore the layer created in #1
402 * The imagefilter is passed the buffer/surface from the layer (now filled with the
403 * src pixels of the primitive). It returns a new "filtered" buffer, which we
404 * draw onto the previous layer using the xfermode from the original paint.
405 */
reed@google.com8926b162012-03-23 15:36:36 +0000406 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500407 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700408 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700409 SkRect storage;
410 if (rawBounds) {
411 // Make rawBounds include all paint outsets except for those due to image filters.
412 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
413 }
reedbfd5f172016-01-07 11:28:08 -0800414 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700415 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700416 fTempLayerForImageFilter = true;
417 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000418 }
419
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000420 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500421 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000422 fIsSimple = false;
423 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700424 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000425 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400426 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000427 }
428 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000429
reed@android.com8a1c16f2008-12-17 15:59:43 +0000430 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700431 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000432 fCanvas->internalRestore();
433 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000434 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000436
reed@google.com4e2b3d32011-04-07 14:18:59 +0000437 const SkPaint& paint() const {
438 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400439 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000440 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000442
Ben Wagner2c312c42018-06-27 14:46:46 -0400443 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000444 if (fDone) {
445 return false;
446 } else if (fIsSimple) {
447 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000448 return !fPaint->nothingToDraw();
449 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400450 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000451 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000452 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000453
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500455 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700456 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000457 SkCanvas* fCanvas;
458 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000459 const SkPaint* fPaint;
460 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700461 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000462 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000463 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000464 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400465 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000466
Ben Wagner2c312c42018-06-27 14:46:46 -0400467 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000468};
469
Ben Wagner2c312c42018-06-27 14:46:46 -0400470bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700471 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000472 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400473 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000474
reeddbc3cef2015-04-29 12:18:57 -0700475 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
476 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400477 // never want our downstream clients (i.e. devices) to see loopers
478 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000479
reed5c476fb2015-04-20 08:04:21 -0700480 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700481 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700482 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000483 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000484
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000485 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000486 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000487 return false;
488 }
reed@google.com129ec222012-05-15 13:24:09 +0000489 fPaint = paint;
490
491 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400492 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000493 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000494 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000495 return true;
496}
497
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498////////// macros to place around the internal draw calls //////////////////
499
reed3aafe112016-08-18 12:45:34 -0700500#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
501 this->predrawNotify(); \
502 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400503 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800504 SkDrawIter iter(this);
505
506
Ben Wagner2c312c42018-06-27 14:46:46 -0400507#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000508 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700509 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400510 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000511 SkDrawIter iter(this);
512
Ben Wagner2c312c42018-06-27 14:46:46 -0400513#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000514 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700515 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400516 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000518
Ben Wagner2c312c42018-06-27 14:46:46 -0400519#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700520 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700521 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400522 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700523 SkDrawIter iter(this);
524
reed@google.com4e2b3d32011-04-07 14:18:59 +0000525#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526
527////////////////////////////////////////////////////////////////////////////
528
msarettfbfa2582016-08-12 08:29:08 -0700529static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
530 if (bounds.isEmpty()) {
531 return SkRect::MakeEmpty();
532 }
533
534 // Expand bounds out by 1 in case we are anti-aliasing. We store the
535 // bounds as floats to enable a faster quick reject implementation.
536 SkRect dst;
537 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
538 return dst;
539}
540
mtkleinfeaadee2015-04-08 11:25:48 -0700541void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
542 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700543 fMCRec->reset(bounds);
544
545 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500546 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400547 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700548 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700549 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700550}
551
Hal Canary363a3f82018-10-04 11:04:48 -0400552void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000553 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800554 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700555 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556
557 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500558 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500559 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700560 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000561
reeda499f902015-05-01 09:34:31 -0700562 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
563 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400564 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700565
reed@android.com8a1c16f2008-12-17 15:59:43 +0000566 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000567
halcanary96fcdcc2015-08-27 07:41:13 -0700568 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000569
reedf92c8662014-08-18 08:02:43 -0700570 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700571 // The root device and the canvas should always have the same pixel geometry
572 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800573 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700574 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500575
Mike Reedc42a1cd2017-02-14 14:25:14 -0500576 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700577 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400578
Herb Derby59d997a2018-06-07 12:44:09 -0400579 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580}
581
reed@google.comcde92112011-07-06 20:00:52 +0000582SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000583 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700584 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000585{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000586 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000587
Hal Canary363a3f82018-10-04 11:04:48 -0400588 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000589}
590
reed96a857e2015-01-25 10:33:58 -0800591SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000592 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800593 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000594{
595 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400596 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400597 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700598}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000599
Hal Canary363a3f82018-10-04 11:04:48 -0400600SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700601 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700602 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700603{
604 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700605
Mike Reed566e53c2017-03-10 10:49:45 -0500606 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400607 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700608}
609
Herb Derbyefe39bc2018-05-01 17:06:20 -0400610SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000611 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700612 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000613{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700615
Hal Canary363a3f82018-10-04 11:04:48 -0400616 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700617}
618
reed4a8126e2014-09-22 07:29:03 -0700619SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700620 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700621 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700622{
623 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700624
Mike Reed910ca0f2018-04-25 13:04:05 -0400625 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400626 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700627}
reed29c857d2014-09-21 10:25:07 -0700628
Mike Reed356f7c22017-01-10 11:58:39 -0500629SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
630 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700631 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
632 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500633 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700634{
635 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700636
Mike Reed910ca0f2018-04-25 13:04:05 -0400637 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400638 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000639}
640
Mike Reed356f7c22017-01-10 11:58:39 -0500641SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
642
Matt Sarett31f99ce2017-04-11 08:46:01 -0400643#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
644SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
645 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
646 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
647 , fAllocator(nullptr)
648{
649 inc_canvas();
650
651 SkBitmap tmp(bitmap);
652 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400653 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400654 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400655}
656#endif
657
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658SkCanvas::~SkCanvas() {
659 // free up the contents of our deque
660 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000661
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 this->internalRestore(); // restore the last, since we're going away
663
halcanary385fe4d2015-08-26 13:07:48 -0700664 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000665
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666 dec_canvas();
667}
668
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000669SkMetaData& SkCanvas::getMetaData() {
670 // metadata users are rare, so we lazily allocate it. If that changes we
671 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700672 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000673 fMetaData = new SkMetaData;
674 }
675 return *fMetaData;
676}
677
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678///////////////////////////////////////////////////////////////////////////////
679
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000680void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700681 this->onFlush();
682}
683
684void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000685 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000686 if (device) {
687 device->flush();
688 }
689}
690
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000691SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000692 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000693 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
694}
695
senorblancoafc7cce2016-02-02 18:44:15 -0800696SkIRect SkCanvas::getTopLayerBounds() const {
697 SkBaseDevice* d = this->getTopDevice();
698 if (!d) {
699 return SkIRect::MakeEmpty();
700 }
701 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
702}
703
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000704SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000705 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000706 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000707 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400708 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709}
710
Florin Malita0ed3b642017-01-13 16:56:38 +0000711SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400712 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000713}
714
Mike Reed353196f2017-07-21 11:01:18 -0400715bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000716 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400717 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000718}
719
Mike Reed353196f2017-07-21 11:01:18 -0400720bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
721 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400722}
723
724bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
725 SkPixmap pm;
726 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
727}
728
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000729bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400730 SkPixmap pm;
731 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700732 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000733 }
734 return false;
735}
736
Matt Sarett03dd6d52017-01-23 12:15:09 -0500737bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000738 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000739 SkBaseDevice* device = this->getDevice();
740 if (!device) {
741 return false;
742 }
743
Matt Sarett03dd6d52017-01-23 12:15:09 -0500744 // This check gives us an early out and prevents generation ID churn on the surface.
745 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
746 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
747 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
748 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000749 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000750
Matt Sarett03dd6d52017-01-23 12:15:09 -0500751 // Tell our owning surface to bump its generation ID.
752 const bool completeOverwrite =
753 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700754 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700755
Matt Sarett03dd6d52017-01-23 12:15:09 -0500756 // This can still fail, most notably in the case of a invalid color type or alpha type
757 // conversion. We could pull those checks into this function and avoid the unnecessary
758 // generation ID bump. But then we would be performing those checks twice, since they
759 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400760 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000761}
reed@google.com51df9e32010-12-23 19:29:18 +0000762
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763//////////////////////////////////////////////////////////////////////////////
764
reed2ff1fce2014-12-11 07:07:37 -0800765void SkCanvas::checkForDeferredSave() {
766 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800767 this->doSave();
768 }
769}
770
reedf0090cb2014-11-26 08:55:51 -0800771int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800772#ifdef SK_DEBUG
773 int count = 0;
774 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
775 for (;;) {
776 const MCRec* rec = (const MCRec*)iter.next();
777 if (!rec) {
778 break;
779 }
780 count += 1 + rec->fDeferredSaveCount;
781 }
782 SkASSERT(count == fSaveCount);
783#endif
784 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800785}
786
787int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800788 fSaveCount += 1;
789 fMCRec->fDeferredSaveCount += 1;
790 return this->getSaveCount() - 1; // return our prev value
791}
792
793void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800794 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700795
796 SkASSERT(fMCRec->fDeferredSaveCount > 0);
797 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800798 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800799}
800
801void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800802 if (fMCRec->fDeferredSaveCount > 0) {
803 SkASSERT(fSaveCount > 1);
804 fSaveCount -= 1;
805 fMCRec->fDeferredSaveCount -= 1;
806 } else {
807 // check for underflow
808 if (fMCStack.count() > 1) {
809 this->willRestore();
810 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700811 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800812 this->internalRestore();
813 this->didRestore();
814 }
reedf0090cb2014-11-26 08:55:51 -0800815 }
816}
817
818void SkCanvas::restoreToCount(int count) {
819 // sanity check
820 if (count < 1) {
821 count = 1;
822 }
mtkleinf0f14112014-12-12 08:46:25 -0800823
reedf0090cb2014-11-26 08:55:51 -0800824 int n = this->getSaveCount() - count;
825 for (int i = 0; i < n; ++i) {
826 this->restore();
827 }
828}
829
reed2ff1fce2014-12-11 07:07:37 -0800830void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700832 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000834
Mike Reedc42a1cd2017-02-14 14:25:14 -0500835 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836}
837
reed4960eee2015-12-18 07:09:18 -0800838bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400839 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000840}
841
reed4960eee2015-12-18 07:09:18 -0800842bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700843 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500844 SkIRect clipBounds = this->getDeviceClipBounds();
845 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000846 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000847 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000848
reed96e657d2015-03-10 17:30:07 -0700849 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
850
Robert Phillips12078432018-05-17 11:17:39 -0400851 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
852 // If the image filter DAG affects transparent black then we will need to render
853 // out to the clip bounds
854 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000855 }
Robert Phillips12078432018-05-17 11:17:39 -0400856
857 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700858 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000859 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700860 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400861 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000862 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400863 inputSaveLayerBounds = clipBounds;
864 }
865
866 if (imageFilter) {
867 // expand the clip bounds by the image filter DAG to include extra content that might
868 // be required by the image filters.
869 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
870 SkImageFilter::kReverse_MapDirection,
871 &inputSaveLayerBounds);
872 }
873
874 SkIRect clippedSaveLayerBounds;
875 if (bounds) {
876 // For better or for worse, user bounds currently act as a hard clip on the layer's
877 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
878 clippedSaveLayerBounds = inputSaveLayerBounds;
879 } else {
880 // If there are no user bounds, we don't want to artificially restrict the resulting
881 // layer bounds, so allow the expanded clip bounds free reign.
882 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000883 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800884
885 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400886 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800887 if (BoundsAffectsClip(saveLayerFlags)) {
888 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
889 fMCRec->fRasterClip.setEmpty();
890 fDeviceClipBounds.setEmpty();
891 }
892 return false;
893 }
Robert Phillips12078432018-05-17 11:17:39 -0400894 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000895
reed4960eee2015-12-18 07:09:18 -0800896 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700897 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400898 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
899 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000900 }
901
902 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400903 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000904 }
Robert Phillips12078432018-05-17 11:17:39 -0400905
junov@chromium.orga907ac32012-02-24 21:54:07 +0000906 return true;
907}
908
reed4960eee2015-12-18 07:09:18 -0800909int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
910 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000911}
912
reed70ee31b2015-12-10 13:44:45 -0800913int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800914 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
915}
916
Cary Clarke041e312018-03-06 13:00:52 -0500917int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700918 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400919 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
920 // no need for the layer (or any of the draws until the matching restore()
921 this->save();
922 this->clipRect({0,0,0,0});
923 } else {
924 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
925 fSaveCount += 1;
926 this->internalSaveLayer(rec, strategy);
927 }
reed4960eee2015-12-18 07:09:18 -0800928 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800929}
930
Mike Reed148b7fd2018-12-18 17:38:18 -0500931int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
932 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
933 // Assuming clips never expand, if the request bounds is outside of the current clip
934 // there is no need to copy/restore the area, so just devolve back to a regular save.
935 this->save();
936 } else {
937 bool doTheWork = this->onDoSaveBehind(bounds);
938 fSaveCount += 1;
939 this->internalSave();
940 if (doTheWork) {
941 this->internalSaveBehind(bounds);
942 }
943 }
944 return this->getSaveCount() - 1;
945}
946
reeda2217ef2016-07-20 06:04:34 -0700947void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500948 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500949 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700950 SkDraw draw;
951 SkRasterClip rc;
952 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
953 if (!dst->accessPixels(&draw.fDst)) {
954 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800955 }
reeda2217ef2016-07-20 06:04:34 -0700956 draw.fMatrix = &SkMatrix::I();
957 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800958
959 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500960 if (filter) {
961 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
962 }
reeda2217ef2016-07-20 06:04:34 -0700963
Mike Reedc42a1cd2017-02-14 14:25:14 -0500964 int x = src->getOrigin().x() - dstOrigin.x();
965 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700966 auto special = src->snapSpecial();
967 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400968 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700969 }
robertphillips7354a4b2015-12-16 05:08:27 -0800970}
reed70ee31b2015-12-10 13:44:45 -0800971
Mike Kleine083f7c2018-02-07 12:54:27 -0500972static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500973 // Need to force L32 for now if we have an image filter.
974 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
975 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500976 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800977 }
Mike Klein649fb732018-02-26 15:09:16 -0500978
979 SkColorType ct = prev.colorType();
980 if (prev.bytesPerPixel() <= 4) {
981 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
982 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
983 ct = kN32_SkColorType;
984 }
985 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800986}
987
reed4960eee2015-12-18 07:09:18 -0800988void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700989 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800990 const SkRect* bounds = rec.fBounds;
991 const SkPaint* paint = rec.fPaint;
992 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
993
reed8c30a812016-04-20 16:36:51 -0700994 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400995 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700996 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400997 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700998 SkMatrix remainder;
999 SkSize scale;
1000 /*
1001 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1002 * but they do handle scaling. To accommodate this, we do the following:
1003 *
1004 * 1. Stash off the current CTM
1005 * 2. Decompose the CTM into SCALE and REMAINDER
1006 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1007 * contains the REMAINDER
1008 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1009 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1010 * of the original imagefilter, and draw that (via drawSprite)
1011 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1012 *
1013 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1014 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1015 */
reed96a04f32016-04-25 09:25:15 -07001016 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001017 stashedMatrix.decomposeScale(&scale, &remainder))
1018 {
1019 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001020 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001021 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1022 SkPaint* p = lazyP.set(*paint);
1023 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1024 SkFilterQuality::kLow_SkFilterQuality,
1025 sk_ref_sp(imageFilter)));
1026 imageFilter = p->getImageFilter();
1027 paint = p;
1028 }
reed8c30a812016-04-20 16:36:51 -07001029
junov@chromium.orga907ac32012-02-24 21:54:07 +00001030 // do this before we create the layer. We don't call the public save() since
1031 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001032 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001033
junov@chromium.orga907ac32012-02-24 21:54:07 +00001034 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001035 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001036 if (modifiedRec) {
1037 // In this case there will be no layer in which to stash the matrix so we need to
1038 // revert the prior MCRec to its earlier state.
1039 modifiedRec->fMatrix = stashedMatrix;
1040 }
reed2ff1fce2014-12-11 07:07:37 -08001041 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001042 }
1043
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001044 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1045 // the clipRectBounds() call above?
1046 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001047 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001048 }
1049
reed8dc0ccb2015-03-20 06:32:52 -07001050 SkPixelGeometry geo = fProps.pixelGeometry();
1051 if (paint) {
reed76033be2015-03-14 10:54:31 -07001052 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001053 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001054 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001055 }
1056 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001057
robertphillips5139e502016-07-19 05:10:40 -07001058 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001059 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001060 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001061 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001062 }
reedb2db8982014-11-13 12:41:02 -08001063
Mike Kleine083f7c2018-02-07 12:54:27 -05001064 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001065
Hal Canary704cd322016-11-07 14:13:52 -05001066 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001067 {
reed70ee31b2015-12-10 13:44:45 -08001068 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001069 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001070 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001071 const bool trackCoverage =
1072 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001073 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001074 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001075 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001076 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001077 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1078 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001079 return;
reed61f501f2015-04-29 08:34:00 -07001080 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001081 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001082 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001083
Mike Reedb43a3e02017-02-11 10:18:58 -05001084 // only have a "next" if this new layer doesn't affect the clip (rare)
1085 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 fMCRec->fLayer = layer;
1087 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001088
Mike Reedc61abee2017-02-28 17:45:27 -05001089 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001090 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001091 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001092 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001093
Mike Reedc42a1cd2017-02-14 14:25:14 -05001094 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1095
1096 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1097 if (layer->fNext) {
1098 // need to punch a hole in the previous device, so we don't draw there, given that
1099 // the new top-layer will allow drawing to happen "below" it.
1100 SkRegion hole(ir);
1101 do {
1102 layer = layer->fNext;
1103 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1104 } while (layer->fNext);
1105 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106}
1107
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001108int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001109 if (0xFF == alpha) {
1110 return this->saveLayer(bounds, nullptr);
1111 } else {
1112 SkPaint tmpPaint;
1113 tmpPaint.setAlpha(alpha);
1114 return this->saveLayer(bounds, &tmpPaint);
1115 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001116}
1117
Mike Reed148b7fd2018-12-18 17:38:18 -05001118void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1119 SkIRect devBounds;
1120 if (localBounds) {
1121 SkRect tmp;
1122 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1123 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1124 devBounds.setEmpty();
1125 }
1126 } else {
1127 devBounds = this->getDeviceClipBounds();
1128 }
1129 if (devBounds.isEmpty()) {
1130 return;
1131 }
1132
1133 SkBaseDevice* device = this->getTopDevice();
1134 if (nullptr == device) { // Do we still need this check???
1135 return;
1136 }
1137
1138 // need the bounds relative to the device itself
1139 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1140
1141 auto backImage = device->snapBackImage(devBounds);
1142 if (!backImage) {
1143 return;
1144 }
1145
1146 // we really need the save, so we can wack the fMCRec
1147 this->checkForDeferredSave();
1148
1149 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1150
1151 SkPaint paint;
1152 paint.setBlendMode(SkBlendMode::kClear);
1153 if (localBounds) {
1154 this->drawRect(*localBounds, paint);
1155 } else {
1156 this->drawPaint(paint);
1157 }
1158}
1159
reed@android.com8a1c16f2008-12-17 15:59:43 +00001160void SkCanvas::internalRestore() {
1161 SkASSERT(fMCStack.count() != 0);
1162
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001163 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001164 DeviceCM* layer = fMCRec->fLayer; // may be null
1165 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001166 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001167
Mike Reed148b7fd2018-12-18 17:38:18 -05001168 // move this out before we do the actual restore
1169 auto backImage = std::move(fMCRec->fBackImage);
1170
reed@android.com8a1c16f2008-12-17 15:59:43 +00001171 // now do the normal restore()
1172 fMCRec->~MCRec(); // balanced in save()
1173 fMCStack.pop_back();
1174 fMCRec = (MCRec*)fMCStack.back();
1175
Mike Reedc42a1cd2017-02-14 14:25:14 -05001176 if (fMCRec) {
1177 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1178 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001179
Mike Reed148b7fd2018-12-18 17:38:18 -05001180 if (backImage) {
1181 SkPaint paint;
1182 paint.setBlendMode(SkBlendMode::kDstOver);
1183 const int x = backImage->fLoc.x();
1184 const int y = backImage->fLoc.y();
1185 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1186 nullptr, SkMatrix::I());
1187 }
1188
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1190 since if we're being recorded, we don't want to record this (the
1191 recorder will have already recorded the restore).
1192 */
bsalomon49f085d2014-09-05 13:34:00 -07001193 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001194 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001195 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001196 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001197 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001198 layer->fPaint.get(),
1199 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001200 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001201 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001202 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001203 delete layer;
reedb679ca82015-04-07 04:40:48 -07001204 } else {
1205 // we're at the root
reeda499f902015-05-01 09:34:31 -07001206 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001207 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001208 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001209 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001210 }
msarettfbfa2582016-08-12 08:29:08 -07001211
1212 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001213 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001214 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1215 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216}
1217
reede8f30622016-03-23 18:59:25 -07001218sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001219 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001220 props = &fProps;
1221 }
1222 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001223}
1224
reede8f30622016-03-23 18:59:25 -07001225sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001226 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001227 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001228}
1229
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001230SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001231 return this->onImageInfo();
1232}
1233
1234SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001235 SkBaseDevice* dev = this->getDevice();
1236 if (dev) {
1237 return dev->imageInfo();
1238 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001239 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001240 }
1241}
1242
brianosman898235c2016-04-06 07:38:23 -07001243bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001244 return this->onGetProps(props);
1245}
1246
1247bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001248 SkBaseDevice* dev = this->getDevice();
1249 if (dev) {
1250 if (props) {
1251 *props = fProps;
1252 }
1253 return true;
1254 } else {
1255 return false;
1256 }
1257}
1258
reed6ceeebd2016-03-09 14:26:26 -08001259bool SkCanvas::peekPixels(SkPixmap* pmap) {
1260 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001261}
1262
reed884e97c2015-05-26 11:31:54 -07001263bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001264 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001265 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001266}
1267
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001268void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001269 SkPixmap pmap;
1270 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001271 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001272 }
1273 if (info) {
1274 *info = pmap.info();
1275 }
1276 if (rowBytes) {
1277 *rowBytes = pmap.rowBytes();
1278 }
1279 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001280 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001281 }
reed884e97c2015-05-26 11:31:54 -07001282 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001283}
1284
reed884e97c2015-05-26 11:31:54 -07001285bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001286 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001287 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001288}
1289
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291
Florin Malita53f77bd2017-04-28 13:48:37 -04001292void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1293 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001295 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296 paint = &tmp;
1297 }
reed@google.com4b226022011-01-11 18:32:13 +00001298
Ben Wagner2c312c42018-06-27 14:46:46 -04001299 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001300
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001302 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001303 paint = &looper.paint();
1304 SkImageFilter* filter = paint->getImageFilter();
1305 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001306 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001307 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1308 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001309 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1310 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001311 }
reed@google.com76dd2772012-01-05 21:15:07 +00001312 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001313 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315 }
reeda2217ef2016-07-20 06:04:34 -07001316
reed@google.com4e2b3d32011-04-07 14:18:59 +00001317 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318}
1319
reed32704672015-12-16 08:27:10 -08001320/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001321
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001322void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001323 if (dx || dy) {
1324 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001325 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001326
reedfe69b502016-09-12 06:31:48 -07001327 // Translate shouldn't affect the is-scale-translateness of the matrix.
1328 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001329
Mike Reedc42a1cd2017-02-14 14:25:14 -05001330 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001331
reedfe69b502016-09-12 06:31:48 -07001332 this->didTranslate(dx,dy);
1333 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334}
1335
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001336void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001337 SkMatrix m;
1338 m.setScale(sx, sy);
1339 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340}
1341
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001342void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001343 SkMatrix m;
1344 m.setRotate(degrees);
1345 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346}
1347
bungeman7438bfc2016-07-12 15:01:19 -07001348void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1349 SkMatrix m;
1350 m.setRotate(degrees, px, py);
1351 this->concat(m);
1352}
1353
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001354void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001355 SkMatrix m;
1356 m.setSkew(sx, sy);
1357 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001358}
1359
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001360void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001361 if (matrix.isIdentity()) {
1362 return;
1363 }
1364
reed2ff1fce2014-12-11 07:07:37 -08001365 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001366 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001367 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001368
Mike Reed7627fa52017-02-08 10:07:53 -05001369 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001370
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001371 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001372}
1373
reed8c30a812016-04-20 16:36:51 -07001374void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001375 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001376 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001377
Mike Reedc42a1cd2017-02-14 14:25:14 -05001378 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001379}
1380
1381void SkCanvas::setMatrix(const SkMatrix& matrix) {
1382 this->checkForDeferredSave();
1383 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001384 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385}
1386
reed@android.com8a1c16f2008-12-17 15:59:43 +00001387void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001388 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389}
1390
1391//////////////////////////////////////////////////////////////////////////////
1392
Mike Reedc1f77742016-12-09 09:00:50 -05001393void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001394 if (!rect.isFinite()) {
1395 return;
1396 }
reed2ff1fce2014-12-11 07:07:37 -08001397 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001398 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1399 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001400}
1401
Mike Reedc1f77742016-12-09 09:00:50 -05001402void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001403 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001404
Mike Reed7627fa52017-02-08 10:07:53 -05001405 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001406
reedc64eff52015-11-21 12:39:45 -08001407 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001408 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1409 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001410 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001411}
1412
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001413void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1414 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001415 if (fClipRestrictionRect.isEmpty()) {
1416 // we notify the device, but we *dont* resolve deferred saves (since we're just
1417 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001418 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001419 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001420 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001421 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001422 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001423 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001424 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1425 }
1426}
1427
Mike Reedc1f77742016-12-09 09:00:50 -05001428void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001429 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001430 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001431 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001432 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1433 } else {
1434 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001435 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001436}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001437
Mike Reedc1f77742016-12-09 09:00:50 -05001438void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001439 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001440
Brian Salomona3b45d42016-10-03 11:36:16 -04001441 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001442
Mike Reed7627fa52017-02-08 10:07:53 -05001443 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001444
Mike Reed20800c82017-11-15 16:09:04 -05001445 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1446 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001447 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001448}
1449
Mike Reedc1f77742016-12-09 09:00:50 -05001450void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001451 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001452 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001453
1454 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1455 SkRect r;
1456 if (path.isRect(&r)) {
1457 this->onClipRect(r, op, edgeStyle);
1458 return;
1459 }
1460 SkRRect rrect;
1461 if (path.isOval(&r)) {
1462 rrect.setOval(r);
1463 this->onClipRRect(rrect, op, edgeStyle);
1464 return;
1465 }
1466 if (path.isRRect(&rrect)) {
1467 this->onClipRRect(rrect, op, edgeStyle);
1468 return;
1469 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001470 }
robertphillips39f05382015-11-24 09:30:12 -08001471
1472 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001473}
1474
Mike Reedc1f77742016-12-09 09:00:50 -05001475void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001476 AutoValidateClip avc(this);
1477
Brian Salomona3b45d42016-10-03 11:36:16 -04001478 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001479
Mike Reed7627fa52017-02-08 10:07:53 -05001480 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001481
Brian Salomona3b45d42016-10-03 11:36:16 -04001482 const SkPath* rasterClipPath = &path;
1483 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001484 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1485 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001486 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001487}
1488
Mike Reedc1f77742016-12-09 09:00:50 -05001489void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001490 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001491 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001492}
1493
Mike Reedc1f77742016-12-09 09:00:50 -05001494void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001495 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001496
reed@google.com5c3d1472011-02-22 19:12:23 +00001497 AutoValidateClip avc(this);
1498
Mike Reed20800c82017-11-15 16:09:04 -05001499 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001500 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501}
1502
reed@google.com819c9212011-02-23 18:56:55 +00001503#ifdef SK_DEBUG
1504void SkCanvas::validateClip() const {
1505 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001506 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001507 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001508 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001509 return;
1510 }
reed@google.com819c9212011-02-23 18:56:55 +00001511}
1512#endif
1513
Mike Reeda1361362017-03-07 09:37:29 -05001514bool SkCanvas::androidFramework_isClipAA() const {
1515 bool containsAA = false;
1516
1517 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1518
1519 return containsAA;
1520}
1521
1522class RgnAccumulator {
1523 SkRegion* fRgn;
1524public:
1525 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1526 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1527 SkIPoint origin = device->getOrigin();
1528 if (origin.x() | origin.y()) {
1529 rgn->translate(origin.x(), origin.y());
1530 }
1531 fRgn->op(*rgn, SkRegion::kUnion_Op);
1532 }
1533};
1534
1535void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1536 RgnAccumulator accum(rgn);
1537 SkRegion tmp;
1538
1539 rgn->setEmpty();
1540 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001541}
1542
reed@google.com5c3d1472011-02-22 19:12:23 +00001543///////////////////////////////////////////////////////////////////////////////
1544
reed@google.com754de5f2014-02-24 19:38:20 +00001545bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001546 return fMCRec->fRasterClip.isEmpty();
1547
1548 // TODO: should we only use the conservative answer in a recording canvas?
1549#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001550 SkBaseDevice* dev = this->getTopDevice();
1551 // if no device we return true
1552 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001553#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001554}
1555
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001556bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001557 SkBaseDevice* dev = this->getTopDevice();
1558 // if no device we return false
1559 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001560}
1561
msarettfbfa2582016-08-12 08:29:08 -07001562static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1563#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1564 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1565 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1566 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1567 return 0xF != _mm_movemask_ps(mask);
1568#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1569 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1570 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1571 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1572 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1573#else
1574 SkRect devRectAsRect;
1575 SkRect devClipAsRect;
1576 devRect.store(&devRectAsRect.fLeft);
1577 devClip.store(&devClipAsRect.fLeft);
1578 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1579#endif
1580}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001581
msarettfbfa2582016-08-12 08:29:08 -07001582// It's important for this function to not be inlined. Otherwise the compiler will share code
1583// between the fast path and the slow path, resulting in two slow paths.
1584static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1585 const SkMatrix& matrix) {
1586 SkRect deviceRect;
1587 matrix.mapRect(&deviceRect, src);
1588 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1589}
1590
1591bool SkCanvas::quickReject(const SkRect& src) const {
1592#ifdef SK_DEBUG
1593 // Verify that fDeviceClipBounds are set properly.
1594 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001595 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001596 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001597 } else {
msarettfbfa2582016-08-12 08:29:08 -07001598 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001599 }
msarettfbfa2582016-08-12 08:29:08 -07001600
msarett9637ea92016-08-18 14:03:30 -07001601 // Verify that fIsScaleTranslate is set properly.
1602 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001603#endif
1604
msarett9637ea92016-08-18 14:03:30 -07001605 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001606 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1607 }
1608
1609 // We inline the implementation of mapScaleTranslate() for the fast path.
1610 float sx = fMCRec->fMatrix.getScaleX();
1611 float sy = fMCRec->fMatrix.getScaleY();
1612 float tx = fMCRec->fMatrix.getTranslateX();
1613 float ty = fMCRec->fMatrix.getTranslateY();
1614 Sk4f scale(sx, sy, sx, sy);
1615 Sk4f trans(tx, ty, tx, ty);
1616
1617 // Apply matrix.
1618 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1619
1620 // Make sure left < right, top < bottom.
1621 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1622 Sk4f min = Sk4f::Min(ltrb, rblt);
1623 Sk4f max = Sk4f::Max(ltrb, rblt);
1624 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1625 // ARM this sequence generates the fastest (a single instruction).
1626 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1627
1628 // Check if the device rect is NaN or outside the clip.
1629 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001630}
1631
reed@google.com3b3e8952012-08-16 20:53:31 +00001632bool SkCanvas::quickReject(const SkPath& path) const {
1633 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001634}
1635
Mike Klein83c8dd92017-11-28 17:08:45 -05001636SkRect SkCanvas::getLocalClipBounds() const {
1637 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001638 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001639 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001640 }
1641
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001642 SkMatrix inverse;
1643 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001644 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001645 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001646 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001647
Mike Reed42e8c532017-01-23 14:09:13 -05001648 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001649 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001650 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001651
Mike Reedb57b9312018-04-23 12:12:54 -04001652 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001653 inverse.mapRect(&bounds, r);
1654 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001655}
1656
Mike Klein83c8dd92017-11-28 17:08:45 -05001657SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001658 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001659}
1660
reed@android.com8a1c16f2008-12-17 15:59:43 +00001661const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001662 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001663}
1664
Brian Osman11052242016-10-27 14:47:55 -04001665GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001666 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001667 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001668}
1669
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001670GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001671 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001672 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001673}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001674
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001675void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1676 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001677 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001678 if (outer.isEmpty()) {
1679 return;
1680 }
1681 if (inner.isEmpty()) {
1682 this->drawRRect(outer, paint);
1683 return;
1684 }
1685
1686 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001687 // be able to return ...
1688 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001689 //
1690 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001691 if (!outer.getBounds().contains(inner.getBounds())) {
1692 return;
1693 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001694
1695 this->onDrawDRRect(outer, inner, paint);
1696}
1697
reed41af9662015-01-05 07:49:08 -08001698void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001699 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001700 this->onDrawPaint(paint);
1701}
1702
1703void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001704 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001705 // To avoid redundant logic in our culling code and various backends, we always sort rects
1706 // before passing them along.
1707 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001708}
1709
msarettdca352e2016-08-26 06:37:45 -07001710void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001711 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001712 if (region.isEmpty()) {
1713 return;
1714 }
1715
1716 if (region.isRect()) {
1717 return this->drawIRect(region.getBounds(), paint);
1718 }
1719
1720 this->onDrawRegion(region, paint);
1721}
1722
reed41af9662015-01-05 07:49:08 -08001723void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001724 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001725 // To avoid redundant logic in our culling code and various backends, we always sort rects
1726 // before passing them along.
1727 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001728}
1729
1730void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001731 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001732 this->onDrawRRect(rrect, paint);
1733}
1734
1735void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001736 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001737 this->onDrawPoints(mode, count, pts, paint);
1738}
1739
Mike Reede88a1cb2017-03-17 09:50:46 -04001740void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1741 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001742 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001743 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001744 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1745 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001746 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001747}
1748
1749void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001750 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001751 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001752 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1753}
1754
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001755void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1756 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001757 TRACE_EVENT0("skia", TRACE_FUNC);
1758 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001759 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001760 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1761}
1762
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001763void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1764 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001765 TRACE_EVENT0("skia", TRACE_FUNC);
1766 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001767 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001768 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001769}
1770
1771void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001772 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001773 this->onDrawPath(path, paint);
1774}
1775
reeda85d4d02015-05-06 12:56:48 -07001776void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001777 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001778 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001779 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001780}
1781
Mike Reedc4e31092018-01-30 11:15:27 -05001782// Returns true if the rect can be "filled" : non-empty and finite
1783static bool fillable(const SkRect& r) {
1784 SkScalar w = r.width();
1785 SkScalar h = r.height();
1786 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1787}
1788
reede47829b2015-08-06 10:02:53 -07001789void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1790 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001791 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001792 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001793 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001794 return;
1795 }
1796 this->onDrawImageRect(image, &src, dst, paint, constraint);
1797}
reed41af9662015-01-05 07:49:08 -08001798
reed84984ef2015-07-17 07:09:43 -07001799void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1800 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001801 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001802 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001803}
1804
Brian Salomonf08002c2018-10-26 16:15:46 -04001805void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001806 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001807 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001808 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001809}
reede47829b2015-08-06 10:02:53 -07001810
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001811namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001812class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001813public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001814 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1815 if (!origPaint) {
1816 return;
1817 }
1818 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1819 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1820 }
1821 if (origPaint->getMaskFilter()) {
1822 fPaint.writable()->setMaskFilter(nullptr);
1823 }
1824 if (origPaint->isAntiAlias()) {
1825 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001826 }
1827 }
1828
1829 const SkPaint* get() const {
1830 return fPaint;
1831 }
1832
1833private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001834 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001835};
1836} // namespace
1837
reed4c21dc52015-06-25 12:32:03 -07001838void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1839 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001840 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001841 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001842 if (dst.isEmpty()) {
1843 return;
1844 }
msarett552bca92016-08-03 06:53:26 -07001845 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001846 LatticePaint latticePaint(paint);
1847 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001848 } else {
reede47829b2015-08-06 10:02:53 -07001849 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001850 }
reed4c21dc52015-06-25 12:32:03 -07001851}
1852
msarett16882062016-08-16 09:31:08 -07001853void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1854 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001855 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001856 RETURN_ON_NULL(image);
1857 if (dst.isEmpty()) {
1858 return;
1859 }
msarett71df2d72016-09-30 12:41:42 -07001860
1861 SkIRect bounds;
1862 Lattice latticePlusBounds = lattice;
1863 if (!latticePlusBounds.fBounds) {
1864 bounds = SkIRect::MakeWH(image->width(), image->height());
1865 latticePlusBounds.fBounds = &bounds;
1866 }
1867
1868 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001869 LatticePaint latticePaint(paint);
1870 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001871 } else {
1872 this->drawImageRect(image, dst, paint);
1873 }
1874}
1875
Brian Salomon1da5cad2018-11-21 09:21:18 -05001876void SkCanvas::experimental_DrawImageSetV1(const ImageSetEntry imageSet[], int cnt,
1877 SkFilterQuality filterQuality, SkBlendMode mode) {
1878 TRACE_EVENT0("skia", TRACE_FUNC);
1879 RETURN_ON_NULL(imageSet);
1880 RETURN_ON_FALSE(cnt);
1881
Brian Salomond003d222018-11-26 13:25:05 -05001882 this->onDrawImageSet(imageSet, cnt, filterQuality, mode);
Brian Salomon1da5cad2018-11-21 09:21:18 -05001883}
1884
reed41af9662015-01-05 07:49:08 -08001885void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001886 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001887 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001888 return;
1889 }
reed41af9662015-01-05 07:49:08 -08001890 this->onDrawBitmap(bitmap, dx, dy, paint);
1891}
1892
reede47829b2015-08-06 10:02:53 -07001893void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001894 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001895 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001896 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001897 return;
1898 }
reede47829b2015-08-06 10:02:53 -07001899 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001900}
1901
reed84984ef2015-07-17 07:09:43 -07001902void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1903 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001904 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001905}
1906
reede47829b2015-08-06 10:02:53 -07001907void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1908 SrcRectConstraint constraint) {
1909 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1910 constraint);
1911}
reede47829b2015-08-06 10:02:53 -07001912
reed41af9662015-01-05 07:49:08 -08001913void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1914 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001915 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001916 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001917 return;
1918 }
msarett552bca92016-08-03 06:53:26 -07001919 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001920 LatticePaint latticePaint(paint);
1921 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001922 } else {
reeda5517e22015-07-14 10:54:12 -07001923 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001924 }
reed41af9662015-01-05 07:49:08 -08001925}
1926
msarettc573a402016-08-02 08:05:56 -07001927void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1928 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001929 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001930 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001931 return;
1932 }
msarett71df2d72016-09-30 12:41:42 -07001933
1934 SkIRect bounds;
1935 Lattice latticePlusBounds = lattice;
1936 if (!latticePlusBounds.fBounds) {
1937 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1938 latticePlusBounds.fBounds = &bounds;
1939 }
1940
1941 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001942 LatticePaint latticePaint(paint);
1943 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001944 } else {
msarett16882062016-08-16 09:31:08 -07001945 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001946 }
msarettc573a402016-08-02 08:05:56 -07001947}
1948
reed71c3c762015-06-24 10:29:17 -07001949void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001950 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001951 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001952 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001953 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001954 if (count <= 0) {
1955 return;
1956 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001957 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001958 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001959 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001960}
1961
reedf70b5312016-03-04 16:36:20 -08001962void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001963 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001964 if (key) {
1965 this->onDrawAnnotation(rect, key, value);
1966 }
1967}
1968
reede47829b2015-08-06 10:02:53 -07001969void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1970 const SkPaint* paint, SrcRectConstraint constraint) {
1971 if (src) {
1972 this->drawImageRect(image, *src, dst, paint, constraint);
1973 } else {
1974 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1975 dst, paint, constraint);
1976 }
1977}
1978void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1979 const SkPaint* paint, SrcRectConstraint constraint) {
1980 if (src) {
1981 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1982 } else {
1983 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1984 dst, paint, constraint);
1985 }
1986}
1987
Mike Reed4204da22017-05-17 08:53:36 -04001988void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001989 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001990 this->onDrawShadowRec(path, rec);
1991}
1992
1993void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1994 SkPaint paint;
1995 const SkRect& pathBounds = path.getBounds();
1996
Ben Wagner2c312c42018-06-27 14:46:46 -04001997 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001998 while (iter.next()) {
1999 iter.fDevice->drawShadow(path, rec);
2000 }
2001 LOOPER_END
2002}
2003
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004//////////////////////////////////////////////////////////////////////////////
2005// These are the virtual drawing methods
2006//////////////////////////////////////////////////////////////////////////////
2007
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002008void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002009 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002010 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2011 }
2012}
2013
reed41af9662015-01-05 07:49:08 -08002014void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002015 this->internalDrawPaint(paint);
2016}
2017
2018void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002019 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002020
2021 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002022 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002023 }
2024
reed@google.com4e2b3d32011-04-07 14:18:59 +00002025 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002026}
2027
reed41af9662015-01-05 07:49:08 -08002028void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2029 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002030 if ((long)count <= 0) {
2031 return;
2032 }
2033
Mike Reed822128b2017-02-28 16:41:03 -05002034 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002035 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002036 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002037 // special-case 2 points (common for drawing a single line)
2038 if (2 == count) {
2039 r.set(pts[0], pts[1]);
2040 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002041 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002042 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002043 if (!r.isFinite()) {
2044 return;
2045 }
Mike Reed822128b2017-02-28 16:41:03 -05002046 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002047 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2048 return;
2049 }
2050 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002051 }
reed@google.coma584aed2012-05-16 14:06:02 +00002052
halcanary96fcdcc2015-08-27 07:41:13 -07002053 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002054
Ben Wagner2c312c42018-06-27 14:46:46 -04002055 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002056
reed@android.com8a1c16f2008-12-17 15:59:43 +00002057 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002058 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002059 }
reed@google.com4b226022011-01-11 18:32:13 +00002060
reed@google.com4e2b3d32011-04-07 14:18:59 +00002061 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002062}
2063
reed4a167172016-08-18 17:15:25 -07002064static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2065 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07002066 (intptr_t)paint.getLooper() ) != 0;
2067}
2068
reed41af9662015-01-05 07:49:08 -08002069void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002070 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002071 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002072 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002073 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002074 return;
2075 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002076 }
reed@google.com4b226022011-01-11 18:32:13 +00002077
reed4a167172016-08-18 17:15:25 -07002078 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002079 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002080
reed4a167172016-08-18 17:15:25 -07002081 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002082 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002083 }
2084
2085 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002086 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002087 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002088 SkDrawIter iter(this);
2089 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002090 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002091 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002092 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093}
2094
msarett44df6512016-08-25 13:54:30 -07002095void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002096 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002097 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002098 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002099 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2100 return;
2101 }
msarett44df6512016-08-25 13:54:30 -07002102 }
2103
Ben Wagner2c312c42018-06-27 14:46:46 -04002104 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002105
2106 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002107 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002108 }
2109
2110 LOOPER_END
2111}
2112
reed41af9662015-01-05 07:49:08 -08002113void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002114 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002115 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002116 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002117 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002118 return;
2119 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002120 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002121
Ben Wagner2c312c42018-06-27 14:46:46 -04002122 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002123
2124 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002125 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002126 }
2127
2128 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002129}
2130
bsalomonac3aa242016-08-19 11:25:19 -07002131void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2132 SkScalar sweepAngle, bool useCenter,
2133 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002134 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002135 if (paint.canComputeFastBounds()) {
2136 SkRect storage;
2137 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002138 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002139 return;
2140 }
bsalomonac3aa242016-08-19 11:25:19 -07002141 }
2142
Ben Wagner2c312c42018-06-27 14:46:46 -04002143 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002144
2145 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002146 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002147 }
2148
2149 LOOPER_END
2150}
2151
reed41af9662015-01-05 07:49:08 -08002152void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002153 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002154 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002155 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2156 return;
2157 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002158 }
2159
2160 if (rrect.isRect()) {
2161 // call the non-virtual version
2162 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002163 return;
2164 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002165 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002166 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2167 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002168 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002169
Ben Wagner2c312c42018-06-27 14:46:46 -04002170 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002171
2172 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002173 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002174 }
2175
2176 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002177}
2178
Mike Reed822128b2017-02-28 16:41:03 -05002179void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002180 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002181 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002182 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2183 return;
2184 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002185 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002186
Ben Wagner2c312c42018-06-27 14:46:46 -04002187 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002188
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002189 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002190 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002191 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002192
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002193 LOOPER_END
2194}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002195
reed41af9662015-01-05 07:49:08 -08002196void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002197 if (!path.isFinite()) {
2198 return;
2199 }
2200
Mike Reed822128b2017-02-28 16:41:03 -05002201 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002202 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002203 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002204 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2205 return;
2206 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002207 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002208
Mike Reed822128b2017-02-28 16:41:03 -05002209 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002210 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002211 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002212 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002213 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002214 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002215
Ben Wagner2c312c42018-06-27 14:46:46 -04002216 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002217
2218 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002219 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002220 }
2221
reed@google.com4e2b3d32011-04-07 14:18:59 +00002222 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002223}
2224
reed262a71b2015-12-05 13:07:27 -08002225bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002226 if (!paint.getImageFilter()) {
2227 return false;
2228 }
2229
2230 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002231 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002232 return false;
2233 }
2234
2235 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2236 // Once we can filter and the filter will return a result larger than itself, we should be
2237 // able to remove this constraint.
2238 // skbug.com/4526
2239 //
2240 SkPoint pt;
2241 ctm.mapXY(x, y, &pt);
2242 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2243 return ir.contains(fMCRec->fRasterClip.getBounds());
2244}
2245
Mike Reedf441cfc2018-04-11 14:50:16 -04002246// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2247// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2248// null.
2249static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2250 if (paintParam) {
2251 *real = *paintParam;
2252 real->setStyle(SkPaint::kFill_Style);
2253 real->setPathEffect(nullptr);
2254 paintParam = real;
2255 }
2256 return paintParam;
2257}
2258
reeda85d4d02015-05-06 12:56:48 -07002259void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002260 SkPaint realPaint;
2261 paint = init_image_paint(&realPaint, paint);
2262
reeda85d4d02015-05-06 12:56:48 -07002263 SkRect bounds = SkRect::MakeXYWH(x, y,
2264 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002265 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002266 SkRect tmp = bounds;
2267 if (paint) {
2268 paint->computeFastBounds(tmp, &tmp);
2269 }
2270 if (this->quickReject(tmp)) {
2271 return;
2272 }
reeda85d4d02015-05-06 12:56:48 -07002273 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002274 // At this point we need a real paint object. If the caller passed null, then we should
2275 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2276 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2277 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002278
reeda2217ef2016-07-20 06:04:34 -07002279 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002280 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2281 *paint);
2282 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002283 special = this->getDevice()->makeSpecial(image);
2284 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002285 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002286 }
2287 }
2288
reed262a71b2015-12-05 13:07:27 -08002289 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2290
reeda85d4d02015-05-06 12:56:48 -07002291 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002292 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002293 if (special) {
2294 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002295 iter.fDevice->ctm().mapXY(x, y, &pt);
2296 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002297 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002298 SkScalarRoundToInt(pt.fY), pnt,
2299 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002300 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002301 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002302 }
reeda85d4d02015-05-06 12:56:48 -07002303 }
halcanary9d524f22016-03-29 09:03:52 -07002304
reeda85d4d02015-05-06 12:56:48 -07002305 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002306}
2307
reed41af9662015-01-05 07:49:08 -08002308void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002309 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002310 SkPaint realPaint;
2311 paint = init_image_paint(&realPaint, paint);
2312
halcanary96fcdcc2015-08-27 07:41:13 -07002313 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002314 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002315 if (paint) {
2316 paint->computeFastBounds(dst, &storage);
2317 }
2318 if (this->quickReject(storage)) {
2319 return;
2320 }
reeda85d4d02015-05-06 12:56:48 -07002321 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002322 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002323
Ben Wagner2c312c42018-06-27 14:46:46 -04002324 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002325
reeda85d4d02015-05-06 12:56:48 -07002326 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002327 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002328 }
halcanary9d524f22016-03-29 09:03:52 -07002329
reeda85d4d02015-05-06 12:56:48 -07002330 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002331}
2332
reed41af9662015-01-05 07:49:08 -08002333void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002334 SkDEBUGCODE(bitmap.validate();)
2335
reed33366972015-10-08 09:22:02 -07002336 if (bitmap.drawsNothing()) {
2337 return;
2338 }
2339
Mike Reedf441cfc2018-04-11 14:50:16 -04002340 SkPaint realPaint;
2341 init_image_paint(&realPaint, paint);
2342 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002343
Mike Reed822128b2017-02-28 16:41:03 -05002344 SkRect bounds;
2345 bitmap.getBounds(&bounds);
2346 bounds.offset(x, y);
2347 bool canFastBounds = paint->canComputeFastBounds();
2348 if (canFastBounds) {
2349 SkRect storage;
2350 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002351 return;
2352 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002353 }
reed@google.com4b226022011-01-11 18:32:13 +00002354
reeda2217ef2016-07-20 06:04:34 -07002355 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002356 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2357 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002358 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002359 special = this->getDevice()->makeSpecial(bitmap);
2360 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002361 drawAsSprite = false;
2362 }
2363 }
2364
Mike Reed822128b2017-02-28 16:41:03 -05002365 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002366
2367 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002368 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002369 if (special) {
reed262a71b2015-12-05 13:07:27 -08002370 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002371 iter.fDevice->ctm().mapXY(x, y, &pt);
2372 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002373 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002374 SkScalarRoundToInt(pt.fY), pnt,
2375 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002376 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002377 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002378 }
reed33366972015-10-08 09:22:02 -07002379 }
msarettfbfa2582016-08-12 08:29:08 -07002380
reed33366972015-10-08 09:22:02 -07002381 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002382}
2383
reed@google.com9987ec32011-09-07 11:57:52 +00002384// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002385void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002386 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002387 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002388 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002389 return;
2390 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002391
halcanary96fcdcc2015-08-27 07:41:13 -07002392 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002393 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002394 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2395 return;
2396 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002397 }
reed@google.com3d608122011-11-21 15:16:16 +00002398
reed@google.com33535f32012-09-25 15:37:50 +00002399 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002400 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002401 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002402 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002403
Ben Wagner2c312c42018-06-27 14:46:46 -04002404 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002405
reed@google.com33535f32012-09-25 15:37:50 +00002406 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002407 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002408 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002409
reed@google.com33535f32012-09-25 15:37:50 +00002410 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002411}
2412
reed41af9662015-01-05 07:49:08 -08002413void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002414 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002415 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002416 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002417}
2418
reed4c21dc52015-06-25 12:32:03 -07002419void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2420 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002421 SkPaint realPaint;
2422 paint = init_image_paint(&realPaint, paint);
2423
halcanary96fcdcc2015-08-27 07:41:13 -07002424 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002425 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002426 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2427 return;
2428 }
reed@google.com3d608122011-11-21 15:16:16 +00002429 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002430 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002431
Ben Wagner2c312c42018-06-27 14:46:46 -04002432 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002433
reed4c21dc52015-06-25 12:32:03 -07002434 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002435 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002436 }
halcanary9d524f22016-03-29 09:03:52 -07002437
reed4c21dc52015-06-25 12:32:03 -07002438 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002439}
2440
reed41af9662015-01-05 07:49:08 -08002441void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2442 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002443 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002444 SkPaint realPaint;
2445 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002446
halcanary96fcdcc2015-08-27 07:41:13 -07002447 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002448 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002449 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2450 return;
2451 }
reed4c21dc52015-06-25 12:32:03 -07002452 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002453 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002454
Ben Wagner2c312c42018-06-27 14:46:46 -04002455 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002456
reed4c21dc52015-06-25 12:32:03 -07002457 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002458 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002459 }
halcanary9d524f22016-03-29 09:03:52 -07002460
reed4c21dc52015-06-25 12:32:03 -07002461 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002462}
2463
msarett16882062016-08-16 09:31:08 -07002464void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2465 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002466 SkPaint realPaint;
2467 paint = init_image_paint(&realPaint, paint);
2468
msarett16882062016-08-16 09:31:08 -07002469 if (nullptr == paint || paint->canComputeFastBounds()) {
2470 SkRect storage;
2471 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2472 return;
2473 }
2474 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002475 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002476
Ben Wagner2c312c42018-06-27 14:46:46 -04002477 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002478
2479 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002480 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002481 }
2482
2483 LOOPER_END
2484}
2485
Brian Salomond003d222018-11-26 13:25:05 -05002486void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count,
Brian Salomond7065e72018-10-12 11:42:02 -04002487 SkFilterQuality filterQuality, SkBlendMode mode) {
2488 SkPaint paint;
Brian Salomon23356442018-11-30 15:33:19 -05002489 LOOPER_BEGIN(paint, nullptr)
Brian Salomond7065e72018-10-12 11:42:02 -04002490 while (iter.next()) {
Brian Salomond003d222018-11-26 13:25:05 -05002491 iter.fDevice->drawImageSet(imageSet, count, filterQuality, mode);
Brian Salomond7065e72018-10-12 11:42:02 -04002492 }
2493 LOOPER_END
2494}
2495
msarett16882062016-08-16 09:31:08 -07002496void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2497 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002498 SkPaint realPaint;
2499 paint = init_image_paint(&realPaint, paint);
2500
msarett16882062016-08-16 09:31:08 -07002501 if (nullptr == paint || paint->canComputeFastBounds()) {
2502 SkRect storage;
2503 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2504 return;
2505 }
2506 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002507 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002508
Ben Wagner2c312c42018-06-27 14:46:46 -04002509 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002510
2511 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002512 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002513 }
2514
2515 LOOPER_END
2516}
2517
Herb Derby2eacff02018-07-18 13:41:15 -04002518void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[],
reed45561a02016-07-07 12:47:17 -07002519 const SkRect* cullRect, const SkPaint& paint) {
2520 if (cullRect && this->quickReject(*cullRect)) {
2521 return;
2522 }
2523
Ben Wagner2c312c42018-06-27 14:46:46 -04002524 LOOPER_BEGIN(paint, nullptr)
reed45561a02016-07-07 12:47:17 -07002525
2526 while (iter.next()) {
Herb Derby2eacff02018-07-18 13:41:15 -04002527 fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len);
2528 auto list = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb935cf82018-07-26 16:54:18 -04002529 if (!list.empty()) {
2530 auto glyphRun = list[0];
Herb Derby95e17602018-12-06 17:11:43 -05002531 iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform, paint);
Herb Derby2eacff02018-07-18 13:41:15 -04002532 }
reed45561a02016-07-07 12:47:17 -07002533 }
2534
2535 LOOPER_END
2536}
2537
fmalita00d5c2c2014-08-21 08:53:26 -07002538void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2539 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002540 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002541 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002542 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002543 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002544 SkRect tmp;
2545 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2546 return;
2547 }
2548 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002549 }
2550
fmalita024f9962015-03-03 19:08:17 -08002551 // We cannot filter in the looper as we normally do, because the paint is
2552 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002553 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002554
fmalitaaa1b9122014-08-28 14:32:24 -07002555 while (iter.next()) {
Herb Derbyb983e6b2018-07-13 13:26:29 -04002556 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, SkPoint::Make(x, y));
2557 iter.fDevice->drawGlyphRunList(fScratchGlyphRunBuilder->useGlyphRunList());
fmalita00d5c2c2014-08-21 08:53:26 -07002558 }
2559
fmalitaaa1b9122014-08-28 14:32:24 -07002560 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002561}
2562
Cary Clark2a475ea2017-04-28 15:35:12 -04002563void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2564 this->drawText(string.c_str(), string.size(), x, y, paint);
2565}
2566
Mike Reed358fcad2018-11-23 15:27:51 -05002567// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002568void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002569 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2570 TRACE_EVENT0("skia", TRACE_FUNC);
2571 if (byteLength) {
2572 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002573 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002574 }
2575}
reed@google.come0d9ce82014-04-23 04:00:17 +00002576void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2577 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002578 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002579 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002580 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002581 const SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
2582 const SkTextEncoding encoding = paint.getTextEncoding();
2583 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
reedac095542016-08-04 15:54:41 -07002584 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002585}
2586void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2587 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002588 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002589 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002590 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002591 const SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
2592 const SkTextEncoding encoding = paint.getTextEncoding();
2593 this->drawTextBlob(SkTextBlob::MakeFromPosText(text, byteLength, pos, font, encoding), 0, 0, paint);
reedac095542016-08-04 15:54:41 -07002594 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002595}
2596void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2597 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002598 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002599 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002600 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002601 const SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
2602 const SkTextEncoding encoding = paint.getTextEncoding();
2603 this->drawTextBlob(SkTextBlob::MakeFromPosTextH(text, byteLength, xpos, constY, font, encoding), 0, 0, paint);
reedac095542016-08-04 15:54:41 -07002604 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002605}
Mike Reed7c8d2e92018-08-27 16:38:05 -04002606
reed45561a02016-07-07 12:47:17 -07002607void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2608 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002609 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002610 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002611 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002612 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2613 }
2614}
fmalita00d5c2c2014-08-21 08:53:26 -07002615void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2616 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002617 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002618 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002619 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002620 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002621}
reed@google.come0d9ce82014-04-23 04:00:17 +00002622
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002623void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002624 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002625 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002626
2627 while (iter.next()) {
2628 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002629 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002630 }
2631
2632 LOOPER_END
2633}
2634
dandovb3c9d1c2014-08-12 08:34:29 -07002635void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002636 const SkPoint texCoords[4], SkBlendMode bmode,
2637 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002638 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002639 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002640 return;
2641 }
mtklein6cfa73a2014-08-13 13:33:49 -07002642
Mike Reedfaba3712016-11-03 14:45:31 -04002643 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002644}
2645
2646void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002647 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002648 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002649 // Since a patch is always within the convex hull of the control points, we discard it when its
2650 // bounding rectangle is completely outside the current clip.
2651 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002652 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002653 if (this->quickReject(bounds)) {
2654 return;
2655 }
mtklein6cfa73a2014-08-13 13:33:49 -07002656
Ben Wagner2c312c42018-06-27 14:46:46 -04002657 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002658
dandovecfff212014-08-04 10:02:00 -07002659 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002660 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002661 }
mtklein6cfa73a2014-08-13 13:33:49 -07002662
dandovecfff212014-08-04 10:02:00 -07002663 LOOPER_END
2664}
2665
reeda8db7282015-07-07 10:22:31 -07002666void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002667#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002668 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002669#endif
reede3b38ce2016-01-08 09:18:44 -08002670 RETURN_ON_NULL(dr);
2671 if (x || y) {
2672 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2673 this->onDrawDrawable(dr, &matrix);
2674 } else {
2675 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002676 }
2677}
2678
reeda8db7282015-07-07 10:22:31 -07002679void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002680#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002681 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002682#endif
reede3b38ce2016-01-08 09:18:44 -08002683 RETURN_ON_NULL(dr);
2684 if (matrix && matrix->isIdentity()) {
2685 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002686 }
reede3b38ce2016-01-08 09:18:44 -08002687 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002688}
2689
2690void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002691 // drawable bounds are no longer reliable (e.g. android displaylist)
2692 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002693 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002694}
2695
reed71c3c762015-06-24 10:29:17 -07002696void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002697 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002698 const SkRect* cull, const SkPaint* paint) {
2699 if (cull && this->quickReject(*cull)) {
2700 return;
2701 }
2702
2703 SkPaint pnt;
2704 if (paint) {
2705 pnt = *paint;
2706 }
halcanary9d524f22016-03-29 09:03:52 -07002707
Ben Wagner2c312c42018-06-27 14:46:46 -04002708 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002709 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002710 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002711 }
2712 LOOPER_END
2713}
2714
reedf70b5312016-03-04 16:36:20 -08002715void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2716 SkASSERT(key);
2717
2718 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002719 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002720 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002721 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002722 }
2723 LOOPER_END
2724}
2725
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726//////////////////////////////////////////////////////////////////////////////
2727// These methods are NOT virtual, and therefore must call back into virtual
2728// methods, rather than actually drawing themselves.
2729//////////////////////////////////////////////////////////////////////////////
2730
reed374772b2016-10-05 17:33:02 -07002731void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002732 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002733 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002734 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 this->drawPaint(paint);
2736}
2737
2738void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002739 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2741}
2742
Mike Reed3661bc92017-02-22 13:21:42 -05002743void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002744 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002745 pts[0].set(x0, y0);
2746 pts[1].set(x1, y1);
2747 this->drawPoints(kLines_PointMode, 2, pts, paint);
2748}
2749
Mike Reed3661bc92017-02-22 13:21:42 -05002750void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 if (radius < 0) {
2752 radius = 0;
2753 }
2754
2755 SkRect r;
2756 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002757 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758}
2759
2760void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2761 const SkPaint& paint) {
2762 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002763 SkRRect rrect;
2764 rrect.setRectXY(r, rx, ry);
2765 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766 } else {
2767 this->drawRect(r, paint);
2768 }
2769}
2770
reed@android.com8a1c16f2008-12-17 15:59:43 +00002771void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2772 SkScalar sweepAngle, bool useCenter,
2773 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002774 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002775 if (oval.isEmpty() || !sweepAngle) {
2776 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777 }
bsalomon21af9ca2016-08-25 12:29:23 -07002778 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779}
2780
reed@android.comf76bacf2009-05-13 14:00:33 +00002781///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002782#ifdef SK_DISABLE_SKPICTURE
2783void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002784
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002785
2786void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2787 const SkPaint* paint) {}
2788#else
Mike Klein88d90712018-01-27 17:30:04 +00002789/**
2790 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2791 * against the playback cost of recursing into the subpicture to get at its actual ops.
2792 *
2793 * For now we pick a conservatively small value, though measurement (and other heuristics like
2794 * the type of ops contained) may justify changing this value.
2795 */
2796#define kMaxPictureOpsToUnrollInsteadOfRef 1
2797
reedd5fa1a42014-08-09 11:08:05 -07002798void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002799 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002800 RETURN_ON_NULL(picture);
2801
reede3b38ce2016-01-08 09:18:44 -08002802 if (matrix && matrix->isIdentity()) {
2803 matrix = nullptr;
2804 }
Mike Klein88d90712018-01-27 17:30:04 +00002805 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2806 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2807 picture->playback(this);
2808 } else {
2809 this->onDrawPicture(picture, matrix, paint);
2810 }
reedd5fa1a42014-08-09 11:08:05 -07002811}
robertphillips9b14f262014-06-04 05:40:44 -07002812
reedd5fa1a42014-08-09 11:08:05 -07002813void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2814 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002815 if (!paint || paint->canComputeFastBounds()) {
2816 SkRect bounds = picture->cullRect();
2817 if (paint) {
2818 paint->computeFastBounds(bounds, &bounds);
2819 }
2820 if (matrix) {
2821 matrix->mapRect(&bounds);
2822 }
2823 if (this->quickReject(bounds)) {
2824 return;
2825 }
2826 }
2827
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002828 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002829 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002831#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002832
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833///////////////////////////////////////////////////////////////////////////////
2834///////////////////////////////////////////////////////////////////////////////
2835
reed3aafe112016-08-18 12:45:34 -07002836SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002837 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002838
2839 SkASSERT(canvas);
2840
reed3aafe112016-08-18 12:45:34 -07002841 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842 fDone = !fImpl->next();
2843}
2844
2845SkCanvas::LayerIter::~LayerIter() {
2846 fImpl->~SkDrawIter();
2847}
2848
2849void SkCanvas::LayerIter::next() {
2850 fDone = !fImpl->next();
2851}
2852
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002853SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002854 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002855}
2856
2857const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002858 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002859}
2860
2861const SkPaint& SkCanvas::LayerIter::paint() const {
2862 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002863 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002864 paint = &fDefaultPaint;
2865 }
2866 return *paint;
2867}
2868
Mike Reedca37f322018-03-08 13:22:16 -05002869SkIRect SkCanvas::LayerIter::clipBounds() const {
2870 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002871}
2872
reed@android.com8a1c16f2008-12-17 15:59:43 +00002873int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2874int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002875
2876///////////////////////////////////////////////////////////////////////////////
2877
Mike Reed5df49342016-11-12 08:06:55 -06002878std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002879 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002880 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002881 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002882 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002883
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002884 SkBitmap bitmap;
2885 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002886 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002887 }
Mike Reed12f77342017-11-08 11:19:52 -05002888
2889 return props ?
2890 skstd::make_unique<SkCanvas>(bitmap, *props) :
2891 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002892}
reedd5fa1a42014-08-09 11:08:05 -07002893
2894///////////////////////////////////////////////////////////////////////////////
2895
Florin Malitaee424ac2016-12-01 12:47:59 -05002896SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002897 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002898
Florin Malita439ace92016-12-02 12:05:41 -05002899SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002900 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002901
Herb Derbyefe39bc2018-05-01 17:06:20 -04002902SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002903 : INHERITED(device) {}
2904
Florin Malitaee424ac2016-12-01 12:47:59 -05002905SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2906 (void)this->INHERITED::getSaveLayerStrategy(rec);
2907 return kNoLayer_SaveLayerStrategy;
2908}
2909
Mike Reed148b7fd2018-12-18 17:38:18 -05002910bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2911 return false;
2912}
2913
Florin Malitaee424ac2016-12-01 12:47:59 -05002914///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002915
reed73603f32016-09-20 08:42:38 -07002916static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2917static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2918static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2919static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2920static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2921static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002922
2923///////////////////////////////////////////////////////////////////////////////////////////////////
2924
2925SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2926 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002927 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002928 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2929 SkIPoint origin = dev->getOrigin();
2930 SkMatrix ctm = this->getTotalMatrix();
2931 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2932
2933 SkIRect clip = fMCRec->fRasterClip.getBounds();
2934 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002935 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002936 clip.setEmpty();
2937 }
2938
2939 fAllocator->updateHandle(handle, ctm, clip);
2940 return handle;
2941 }
2942 return nullptr;
2943}
2944
2945static bool install(SkBitmap* bm, const SkImageInfo& info,
2946 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002947 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002948}
2949
2950SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2951 SkBitmap* bm) {
2952 SkRasterHandleAllocator::Rec rec;
2953 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2954 return nullptr;
2955 }
2956 return rec.fHandle;
2957}
2958
2959std::unique_ptr<SkCanvas>
2960SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2961 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002962 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002963 return nullptr;
2964 }
2965
2966 SkBitmap bm;
2967 Handle hndl;
2968
2969 if (rec) {
2970 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2971 } else {
2972 hndl = alloc->allocBitmap(info, &bm);
2973 }
2974 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2975}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002976
2977///////////////////////////////////////////////////////////////////////////////////////////////////
2978
2979