blob: ef149f9f89789a7ff2a7ba2ffa0ccc182a97b7b9 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Hal Canaryc640d0d2018-06-13 09:59:02 -04008#include "SkCanvas.h"
9
Herb Derby73fe7b02017-02-08 15:12:19 -050010#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +000011#include "SkBitmapDevice.h"
reedd5fa1a42014-08-09 11:08:05 -070012#include "SkCanvasPriv.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040013#include "SkClipOpPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070014#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070015#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDraw.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkDrawLooper.h"
Herb Derby41f4f312018-06-06 17:45:53 +000018#include "SkGlyphCache.h"
19#include "SkGlyphRun.h"
piotaixrb5fae932014-09-24 13:03:30 -070020#include "SkImage.h"
senorblanco900c3672016-04-27 11:31:23 -070021#include "SkImageFilter.h"
22#include "SkImageFilterCache.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040023#include "SkImage_Base.h"
msarettc573a402016-08-02 08:05:56 -070024#include "SkLatticeIter.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040025#include "SkMSAN.h"
Mike Reed5df49342016-11-12 08:06:55 -060026#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080027#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000028#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050029#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070030#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070031#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070032#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040033#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000034#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040035#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000036#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050037#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080038#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000039#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040040#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000041#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040042#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070043#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000044#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040045#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080046#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040047#include "SkVertices.h"
48
bungemand3ebb482015-08-05 13:57:49 -070049#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000050
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080052#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050053#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000054#endif
55
reede3b38ce2016-01-08 09:18:44 -080056#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050057#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080058
Mike Reed139e5e02017-03-08 11:29:33 -050059///////////////////////////////////////////////////////////////////////////////////////////////////
60
reedc83a2972015-07-16 07:40:45 -070061/*
62 * Return true if the drawing this rect would hit every pixels in the canvas.
63 *
64 * Returns false if
65 * - rect does not contain the canvas' bounds
66 * - paint is not fill
67 * - paint would blur or otherwise change the coverage of the rect
68 */
69bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
70 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070071 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
72 (int)kNone_ShaderOverrideOpacity,
73 "need_matching_enums0");
74 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
75 (int)kOpaque_ShaderOverrideOpacity,
76 "need_matching_enums1");
77 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
78 (int)kNotOpaque_ShaderOverrideOpacity,
79 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070080
81 const SkISize size = this->getBaseLayerSize();
82 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050083
84 // if we're clipped at all, we can't overwrite the entire surface
85 {
86 SkBaseDevice* base = this->getDevice();
87 SkBaseDevice* top = this->getTopDevice();
88 if (base != top) {
89 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
90 }
91 if (!base->clipIsWideOpen()) {
92 return false;
93 }
reedc83a2972015-07-16 07:40:45 -070094 }
95
96 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070097 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070098 return false; // conservative
99 }
halcanaryc5769b22016-08-10 07:13:21 -0700100
101 SkRect devRect;
102 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
103 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700104 return false;
105 }
106 }
107
108 if (paint) {
109 SkPaint::Style paintStyle = paint->getStyle();
110 if (!(paintStyle == SkPaint::kFill_Style ||
111 paintStyle == SkPaint::kStrokeAndFill_Style)) {
112 return false;
113 }
114 if (paint->getMaskFilter() || paint->getLooper()
115 || paint->getPathEffect() || paint->getImageFilter()) {
116 return false; // conservative
117 }
118 }
119 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
120}
121
122///////////////////////////////////////////////////////////////////////////////////////////////////
123
reed@google.comda17f752012-08-16 18:27:05 +0000124// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125//#define SK_TRACE_SAVERESTORE
126
127#ifdef SK_TRACE_SAVERESTORE
128 static int gLayerCounter;
129 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
130 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
131
132 static int gRecCounter;
133 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
134 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
135
136 static int gCanvasCounter;
137 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
138 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
139#else
140 #define inc_layer()
141 #define dec_layer()
142 #define inc_rec()
143 #define dec_rec()
144 #define inc_canvas()
145 #define dec_canvas()
146#endif
147
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000148typedef SkTLazy<SkPaint> SkLazyPaint;
149
reedc83a2972015-07-16 07:40:45 -0700150void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000151 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700152 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
153 ? SkSurface::kDiscard_ContentChangeMode
154 : SkSurface::kRetain_ContentChangeMode);
155 }
156}
157
158void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
159 ShaderOverrideOpacity overrideOpacity) {
160 if (fSurfaceBase) {
161 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
162 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
163 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
164 // and therefore we don't care which mode we're in.
165 //
166 if (fSurfaceBase->outstandingImageSnapshot()) {
167 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
168 mode = SkSurface::kDiscard_ContentChangeMode;
169 }
170 }
171 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000172 }
173}
174
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000177/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 The clip/matrix/proc are fields that reflect the top of the save/restore
179 stack. Whenever the canvas changes, it marks a dirty flag, and then before
180 these are used (assuming we're not on a layer) we rebuild these cache
181 values: they reflect the top of the save stack, but translated and clipped
182 by the device's XY offset and bitmap-bounds.
183*/
184struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400185 DeviceCM* fNext;
186 sk_sp<SkBaseDevice> fDevice;
187 SkRasterClip fClip;
188 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
189 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400190 sk_sp<SkImage> fClipImage;
191 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192
Florin Malita53f77bd2017-04-28 13:48:37 -0400193 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000194 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700195 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400196 , fDevice(std::move(device))
197 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700198 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000199 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400200 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400201 {}
reed@google.com4b226022011-01-11 18:32:13 +0000202
mtkleinfeaadee2015-04-08 11:25:48 -0700203 void reset(const SkIRect& bounds) {
204 SkASSERT(!fPaint);
205 SkASSERT(!fNext);
206 SkASSERT(fDevice);
207 fClip.setRect(bounds);
208 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209};
210
211/* This is the record we keep for each save/restore level in the stack.
212 Since a level optionally copies the matrix and/or stack, we have pointers
213 for these fields. If the value is copied for this level, the copy is
214 stored in the ...Storage field, and the pointer points to that. If the
215 value is not copied for this level, we ignore ...Storage, and just point
216 at the corresponding value in the previous level in the stack.
217*/
218class SkCanvas::MCRec {
219public:
reedd9544982014-09-09 18:46:22 -0700220 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 /* If there are any layers in the stack, this points to the top-most
222 one that is at or below this level in the stack (so we know what
223 bitmap/device to draw into from this level. This value is NOT
224 reference counted, since the real owner is either our fLayer field,
225 or a previous one in a lower level.)
226 */
Mike Reeda1361362017-03-07 09:37:29 -0500227 DeviceCM* fTopLayer;
228 SkConservativeClip fRasterClip;
229 SkMatrix fMatrix;
230 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231
Mike Reeda1361362017-03-07 09:37:29 -0500232 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700233 fLayer = nullptr;
234 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800235 fMatrix.reset();
236 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700237
reedd9544982014-09-09 18:46:22 -0700238 // don't bother initializing fNext
239 inc_rec();
240 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400241 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700242 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700243 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800244 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 // don't bother initializing fNext
247 inc_rec();
248 }
249 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700250 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 dec_rec();
252 }
mtkleinfeaadee2015-04-08 11:25:48 -0700253
254 void reset(const SkIRect& bounds) {
255 SkASSERT(fLayer);
256 SkASSERT(fDeferredSaveCount == 0);
257
258 fMatrix.reset();
259 fRasterClip.setRect(bounds);
260 fLayer->reset(bounds);
261 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262};
263
Mike Reeda1361362017-03-07 09:37:29 -0500264class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265public:
Mike Reeda1361362017-03-07 09:37:29 -0500266 SkDrawIter(SkCanvas* canvas)
267 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
268 {}
reed@google.com4b226022011-01-11 18:32:13 +0000269
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000271 const DeviceCM* rec = fCurrLayer;
272 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400273 fDevice = rec->fDevice.get();
274 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700276 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 return true;
278 }
279 return false;
280 }
reed@google.com4b226022011-01-11 18:32:13 +0000281
reed@google.com6f8f2922011-03-04 22:27:10 +0000282 int getX() const { return fDevice->getOrigin().x(); }
283 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000285
Mike Reed99330ba2017-02-22 11:01:08 -0500286 SkBaseDevice* fDevice;
287
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 const DeviceCM* fCurrLayer;
290 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291};
292
Florin Malita713b8ef2017-04-28 10:57:24 -0400293#define FOR_EACH_TOP_DEVICE( code ) \
294 do { \
295 DeviceCM* layer = fMCRec->fTopLayer; \
296 while (layer) { \
297 SkBaseDevice* device = layer->fDevice.get(); \
298 if (device) { \
299 code; \
300 } \
301 layer = layer->fNext; \
302 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500303 } while (0)
304
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305/////////////////////////////////////////////////////////////////////////////
306
reeddbc3cef2015-04-29 12:18:57 -0700307static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
308 return lazy->isValid() ? lazy->get() : lazy->set(orig);
309}
310
311/**
312 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700313 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700314 */
reedd053ce92016-03-22 10:17:23 -0700315static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700316 SkImageFilter* imgf = paint.getImageFilter();
317 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700318 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700319 }
320
reedd053ce92016-03-22 10:17:23 -0700321 SkColorFilter* imgCFPtr;
322 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700323 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700324 }
reedd053ce92016-03-22 10:17:23 -0700325 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700326
327 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700328 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700329 // there is no existing paint colorfilter, so we can just return the imagefilter's
330 return imgCF;
331 }
332
333 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
334 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500335 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700336}
337
senorblanco87e066e2015-10-28 11:23:36 -0700338/**
339 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
340 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
341 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
342 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
343 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
344 * conservative "effective" bounds based on the settings in the paint... with one exception. This
345 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
346 * deliberately ignored.
347 */
348static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
349 const SkRect& rawBounds,
350 SkRect* storage) {
351 SkPaint tmpUnfiltered(paint);
352 tmpUnfiltered.setImageFilter(nullptr);
353 if (tmpUnfiltered.canComputeFastBounds()) {
354 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
355 } else {
356 return rawBounds;
357 }
358}
359
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360class AutoDrawLooper {
361public:
senorblanco87e066e2015-10-28 11:23:36 -0700362 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
363 // paint. It's used to determine the size of the offscreen layer for filters.
364 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700365 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700366 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000367 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700368 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000369 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700370 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000371 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372
reedd053ce92016-03-22 10:17:23 -0700373 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700374 if (simplifiedCF) {
375 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700376 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700377 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700378 fPaint = paint;
379 }
380
381 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700382 /**
383 * We implement ImageFilters for a given draw by creating a layer, then applying the
384 * imagefilter to the pixels of that layer (its backing surface/image), and then
385 * we call restore() to xfer that layer to the main canvas.
386 *
387 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
388 * 2. Generate the src pixels:
389 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
390 * return (fPaint). We then draw the primitive (using srcover) into a cleared
391 * buffer/surface.
392 * 3. Restore the layer created in #1
393 * The imagefilter is passed the buffer/surface from the layer (now filled with the
394 * src pixels of the primitive). It returns a new "filtered" buffer, which we
395 * draw onto the previous layer using the xfermode from the original paint.
396 */
reed@google.com8926b162012-03-23 15:36:36 +0000397 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500398 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700399 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700400 SkRect storage;
401 if (rawBounds) {
402 // Make rawBounds include all paint outsets except for those due to image filters.
403 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
404 }
reedbfd5f172016-01-07 11:28:08 -0800405 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700406 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700407 fTempLayerForImageFilter = true;
408 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000409 }
410
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000411 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500412 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000413 fIsSimple = false;
414 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700415 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000416 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400417 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000418 }
419 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000420
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700422 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000423 fCanvas->internalRestore();
424 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000425 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000427
reed@google.com4e2b3d32011-04-07 14:18:59 +0000428 const SkPaint& paint() const {
429 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400430 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000431 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000433
Ben Wagner2c312c42018-06-27 14:46:46 -0400434 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000435 if (fDone) {
436 return false;
437 } else if (fIsSimple) {
438 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000439 return !fPaint->nothingToDraw();
440 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400441 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000442 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000443 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000444
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500446 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700447 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000448 SkCanvas* fCanvas;
449 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000450 const SkPaint* fPaint;
451 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700452 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000453 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000454 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000455 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400456 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000457
Ben Wagner2c312c42018-06-27 14:46:46 -0400458 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459};
460
Ben Wagner2c312c42018-06-27 14:46:46 -0400461bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700462 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000463 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400464 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000465
reeddbc3cef2015-04-29 12:18:57 -0700466 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
467 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400468 // never want our downstream clients (i.e. devices) to see loopers
469 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000470
reed5c476fb2015-04-20 08:04:21 -0700471 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700472 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700473 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000474 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000475
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000476 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000477 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000478 return false;
479 }
reed@google.com129ec222012-05-15 13:24:09 +0000480 fPaint = paint;
481
482 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400483 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000484 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000485 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000486 return true;
487}
488
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489////////// macros to place around the internal draw calls //////////////////
490
reed3aafe112016-08-18 12:45:34 -0700491#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
492 this->predrawNotify(); \
493 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400494 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800495 SkDrawIter iter(this);
496
497
Ben Wagner2c312c42018-06-27 14:46:46 -0400498#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000499 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700500 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400501 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000502 SkDrawIter iter(this);
503
Ben Wagner2c312c42018-06-27 14:46:46 -0400504#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000505 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700506 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400507 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000508 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000509
Ben Wagner2c312c42018-06-27 14:46:46 -0400510#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700511 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700512 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400513 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700514 SkDrawIter iter(this);
515
reed@google.com4e2b3d32011-04-07 14:18:59 +0000516#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517
518////////////////////////////////////////////////////////////////////////////
519
msarettfbfa2582016-08-12 08:29:08 -0700520static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
521 if (bounds.isEmpty()) {
522 return SkRect::MakeEmpty();
523 }
524
525 // Expand bounds out by 1 in case we are anti-aliasing. We store the
526 // bounds as floats to enable a faster quick reject implementation.
527 SkRect dst;
528 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
529 return dst;
530}
531
mtkleinfeaadee2015-04-08 11:25:48 -0700532void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
533 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700534 fMCRec->reset(bounds);
535
536 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500537 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400538 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700539 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700540 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700541}
542
Hal Canary363a3f82018-10-04 11:04:48 -0400543void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000544 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800545 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700546 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000547
548 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500549 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500550 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700551 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552
reeda499f902015-05-01 09:34:31 -0700553 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
554 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400555 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700556
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000558
halcanary96fcdcc2015-08-27 07:41:13 -0700559 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000560
reedf92c8662014-08-18 08:02:43 -0700561 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700562 // The root device and the canvas should always have the same pixel geometry
563 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800564 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700565 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500566
Mike Reedc42a1cd2017-02-14 14:25:14 -0500567 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700568 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400569
Herb Derby59d997a2018-06-07 12:44:09 -0400570 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571}
572
reed@google.comcde92112011-07-06 20:00:52 +0000573SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000574 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700575 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000576{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000577 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000578
Hal Canary363a3f82018-10-04 11:04:48 -0400579 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000580}
581
reed96a857e2015-01-25 10:33:58 -0800582SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000583 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800584 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000585{
586 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400587 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400588 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700589}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000590
Hal Canary363a3f82018-10-04 11:04:48 -0400591SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700592 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700593 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700594{
595 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700596
Mike Reed566e53c2017-03-10 10:49:45 -0500597 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400598 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700599}
600
Herb Derbyefe39bc2018-05-01 17:06:20 -0400601SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000602 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700603 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000604{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000605 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700606
Hal Canary363a3f82018-10-04 11:04:48 -0400607 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700608}
609
reed4a8126e2014-09-22 07:29:03 -0700610SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700611 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700612 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700613{
614 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700615
Mike Reed910ca0f2018-04-25 13:04:05 -0400616 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400617 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700618}
reed29c857d2014-09-21 10:25:07 -0700619
Mike Reed356f7c22017-01-10 11:58:39 -0500620SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
621 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700622 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
623 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500624 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700625{
626 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700627
Mike Reed910ca0f2018-04-25 13:04:05 -0400628 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400629 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000630}
631
Mike Reed356f7c22017-01-10 11:58:39 -0500632SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
633
Matt Sarett31f99ce2017-04-11 08:46:01 -0400634#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
635SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
636 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
637 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
638 , fAllocator(nullptr)
639{
640 inc_canvas();
641
642 SkBitmap tmp(bitmap);
643 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400644 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400645 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400646}
647#endif
648
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649SkCanvas::~SkCanvas() {
650 // free up the contents of our deque
651 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000652
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653 this->internalRestore(); // restore the last, since we're going away
654
halcanary385fe4d2015-08-26 13:07:48 -0700655 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000656
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657 dec_canvas();
658}
659
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000660SkMetaData& SkCanvas::getMetaData() {
661 // metadata users are rare, so we lazily allocate it. If that changes we
662 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700663 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000664 fMetaData = new SkMetaData;
665 }
666 return *fMetaData;
667}
668
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669///////////////////////////////////////////////////////////////////////////////
670
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000671void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700672 this->onFlush();
673}
674
675void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000676 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000677 if (device) {
678 device->flush();
679 }
680}
681
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000682SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000683 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000684 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
685}
686
senorblancoafc7cce2016-02-02 18:44:15 -0800687SkIRect SkCanvas::getTopLayerBounds() const {
688 SkBaseDevice* d = this->getTopDevice();
689 if (!d) {
690 return SkIRect::MakeEmpty();
691 }
692 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
693}
694
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000695SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000697 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000698 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400699 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000700}
701
Florin Malita0ed3b642017-01-13 16:56:38 +0000702SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400703 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000704}
705
Mike Reed353196f2017-07-21 11:01:18 -0400706bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000707 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400708 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000709}
710
Mike Reed353196f2017-07-21 11:01:18 -0400711bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
712 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400713}
714
715bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
716 SkPixmap pm;
717 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
718}
719
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000720bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400721 SkPixmap pm;
722 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700723 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000724 }
725 return false;
726}
727
Matt Sarett03dd6d52017-01-23 12:15:09 -0500728bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000729 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000730 SkBaseDevice* device = this->getDevice();
731 if (!device) {
732 return false;
733 }
734
Matt Sarett03dd6d52017-01-23 12:15:09 -0500735 // This check gives us an early out and prevents generation ID churn on the surface.
736 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
737 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
738 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
739 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000740 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000741
Matt Sarett03dd6d52017-01-23 12:15:09 -0500742 // Tell our owning surface to bump its generation ID.
743 const bool completeOverwrite =
744 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700745 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700746
Matt Sarett03dd6d52017-01-23 12:15:09 -0500747 // This can still fail, most notably in the case of a invalid color type or alpha type
748 // conversion. We could pull those checks into this function and avoid the unnecessary
749 // generation ID bump. But then we would be performing those checks twice, since they
750 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400751 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000752}
reed@google.com51df9e32010-12-23 19:29:18 +0000753
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754//////////////////////////////////////////////////////////////////////////////
755
reed2ff1fce2014-12-11 07:07:37 -0800756void SkCanvas::checkForDeferredSave() {
757 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800758 this->doSave();
759 }
760}
761
reedf0090cb2014-11-26 08:55:51 -0800762int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800763#ifdef SK_DEBUG
764 int count = 0;
765 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
766 for (;;) {
767 const MCRec* rec = (const MCRec*)iter.next();
768 if (!rec) {
769 break;
770 }
771 count += 1 + rec->fDeferredSaveCount;
772 }
773 SkASSERT(count == fSaveCount);
774#endif
775 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800776}
777
778int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800779 fSaveCount += 1;
780 fMCRec->fDeferredSaveCount += 1;
781 return this->getSaveCount() - 1; // return our prev value
782}
783
784void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800785 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700786
787 SkASSERT(fMCRec->fDeferredSaveCount > 0);
788 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800789 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800790}
791
792void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800793 if (fMCRec->fDeferredSaveCount > 0) {
794 SkASSERT(fSaveCount > 1);
795 fSaveCount -= 1;
796 fMCRec->fDeferredSaveCount -= 1;
797 } else {
798 // check for underflow
799 if (fMCStack.count() > 1) {
800 this->willRestore();
801 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700802 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800803 this->internalRestore();
804 this->didRestore();
805 }
reedf0090cb2014-11-26 08:55:51 -0800806 }
807}
808
809void SkCanvas::restoreToCount(int count) {
810 // sanity check
811 if (count < 1) {
812 count = 1;
813 }
mtkleinf0f14112014-12-12 08:46:25 -0800814
reedf0090cb2014-11-26 08:55:51 -0800815 int n = this->getSaveCount() - count;
816 for (int i = 0; i < n; ++i) {
817 this->restore();
818 }
819}
820
reed2ff1fce2014-12-11 07:07:37 -0800821void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700823 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000825
Mike Reedc42a1cd2017-02-14 14:25:14 -0500826 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827}
828
reed4960eee2015-12-18 07:09:18 -0800829bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400830 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831}
832
reed4960eee2015-12-18 07:09:18 -0800833bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700834 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500835 SkIRect clipBounds = this->getDeviceClipBounds();
836 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000837 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000838 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000839
reed96e657d2015-03-10 17:30:07 -0700840 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
841
Robert Phillips12078432018-05-17 11:17:39 -0400842 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
843 // If the image filter DAG affects transparent black then we will need to render
844 // out to the clip bounds
845 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000846 }
Robert Phillips12078432018-05-17 11:17:39 -0400847
848 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700849 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700851 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400852 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400854 inputSaveLayerBounds = clipBounds;
855 }
856
857 if (imageFilter) {
858 // expand the clip bounds by the image filter DAG to include extra content that might
859 // be required by the image filters.
860 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
861 SkImageFilter::kReverse_MapDirection,
862 &inputSaveLayerBounds);
863 }
864
865 SkIRect clippedSaveLayerBounds;
866 if (bounds) {
867 // For better or for worse, user bounds currently act as a hard clip on the layer's
868 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
869 clippedSaveLayerBounds = inputSaveLayerBounds;
870 } else {
871 // If there are no user bounds, we don't want to artificially restrict the resulting
872 // layer bounds, so allow the expanded clip bounds free reign.
873 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800875
876 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400877 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800878 if (BoundsAffectsClip(saveLayerFlags)) {
879 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
880 fMCRec->fRasterClip.setEmpty();
881 fDeviceClipBounds.setEmpty();
882 }
883 return false;
884 }
Robert Phillips12078432018-05-17 11:17:39 -0400885 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000886
reed4960eee2015-12-18 07:09:18 -0800887 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700888 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400889 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
890 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000891 }
892
893 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400894 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000895 }
Robert Phillips12078432018-05-17 11:17:39 -0400896
junov@chromium.orga907ac32012-02-24 21:54:07 +0000897 return true;
898}
899
reed4960eee2015-12-18 07:09:18 -0800900int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
901 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000902}
903
reed70ee31b2015-12-10 13:44:45 -0800904int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800905 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
906}
907
Cary Clarke041e312018-03-06 13:00:52 -0500908int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700909 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400910 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
911 // no need for the layer (or any of the draws until the matching restore()
912 this->save();
913 this->clipRect({0,0,0,0});
914 } else {
915 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
916 fSaveCount += 1;
917 this->internalSaveLayer(rec, strategy);
918 }
reed4960eee2015-12-18 07:09:18 -0800919 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800920}
921
reeda2217ef2016-07-20 06:04:34 -0700922void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500923 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500924 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700925 SkDraw draw;
926 SkRasterClip rc;
927 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
928 if (!dst->accessPixels(&draw.fDst)) {
929 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800930 }
reeda2217ef2016-07-20 06:04:34 -0700931 draw.fMatrix = &SkMatrix::I();
932 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800933
934 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500935 if (filter) {
936 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
937 }
reeda2217ef2016-07-20 06:04:34 -0700938
Mike Reedc42a1cd2017-02-14 14:25:14 -0500939 int x = src->getOrigin().x() - dstOrigin.x();
940 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700941 auto special = src->snapSpecial();
942 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400943 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700944 }
robertphillips7354a4b2015-12-16 05:08:27 -0800945}
reed70ee31b2015-12-10 13:44:45 -0800946
Mike Kleine083f7c2018-02-07 12:54:27 -0500947static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500948 // Need to force L32 for now if we have an image filter.
949 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
950 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500951 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800952 }
Mike Klein649fb732018-02-26 15:09:16 -0500953
954 SkColorType ct = prev.colorType();
955 if (prev.bytesPerPixel() <= 4) {
956 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
957 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
958 ct = kN32_SkColorType;
959 }
960 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800961}
962
reed4960eee2015-12-18 07:09:18 -0800963void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700964 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800965 const SkRect* bounds = rec.fBounds;
966 const SkPaint* paint = rec.fPaint;
967 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
968
reed8c30a812016-04-20 16:36:51 -0700969 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400970 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700971 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400972 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700973 SkMatrix remainder;
974 SkSize scale;
975 /*
976 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
977 * but they do handle scaling. To accommodate this, we do the following:
978 *
979 * 1. Stash off the current CTM
980 * 2. Decompose the CTM into SCALE and REMAINDER
981 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
982 * contains the REMAINDER
983 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
984 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
985 * of the original imagefilter, and draw that (via drawSprite)
986 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
987 *
988 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
989 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
990 */
reed96a04f32016-04-25 09:25:15 -0700991 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -0700992 stashedMatrix.decomposeScale(&scale, &remainder))
993 {
994 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -0400995 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -0700996 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
997 SkPaint* p = lazyP.set(*paint);
998 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
999 SkFilterQuality::kLow_SkFilterQuality,
1000 sk_ref_sp(imageFilter)));
1001 imageFilter = p->getImageFilter();
1002 paint = p;
1003 }
reed8c30a812016-04-20 16:36:51 -07001004
junov@chromium.orga907ac32012-02-24 21:54:07 +00001005 // do this before we create the layer. We don't call the public save() since
1006 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001007 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001008
junov@chromium.orga907ac32012-02-24 21:54:07 +00001009 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001010 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001011 if (modifiedRec) {
1012 // In this case there will be no layer in which to stash the matrix so we need to
1013 // revert the prior MCRec to its earlier state.
1014 modifiedRec->fMatrix = stashedMatrix;
1015 }
reed2ff1fce2014-12-11 07:07:37 -08001016 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001017 }
1018
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001019 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1020 // the clipRectBounds() call above?
1021 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001022 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001023 }
1024
reed8dc0ccb2015-03-20 06:32:52 -07001025 SkPixelGeometry geo = fProps.pixelGeometry();
1026 if (paint) {
reed76033be2015-03-14 10:54:31 -07001027 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001028 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001029 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001030 }
1031 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032
robertphillips5139e502016-07-19 05:10:40 -07001033 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001034 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001035 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001036 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001037 }
reedb2db8982014-11-13 12:41:02 -08001038
Mike Kleine083f7c2018-02-07 12:54:27 -05001039 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001040
Hal Canary704cd322016-11-07 14:13:52 -05001041 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001042 {
reed70ee31b2015-12-10 13:44:45 -08001043 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001044 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001045 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001046 const bool trackCoverage =
1047 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001048 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001049 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001050 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001051 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001052 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1053 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001054 return;
reed61f501f2015-04-29 08:34:00 -07001055 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001056 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001057 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058
Mike Reedb43a3e02017-02-11 10:18:58 -05001059 // only have a "next" if this new layer doesn't affect the clip (rare)
1060 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001061 fMCRec->fLayer = layer;
1062 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001063
Mike Reedc61abee2017-02-28 17:45:27 -05001064 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001065 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001066 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001067 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001068
Mike Reedc42a1cd2017-02-14 14:25:14 -05001069 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1070
1071 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1072 if (layer->fNext) {
1073 // need to punch a hole in the previous device, so we don't draw there, given that
1074 // the new top-layer will allow drawing to happen "below" it.
1075 SkRegion hole(ir);
1076 do {
1077 layer = layer->fNext;
1078 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1079 } while (layer->fNext);
1080 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081}
1082
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001083int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001084 if (0xFF == alpha) {
1085 return this->saveLayer(bounds, nullptr);
1086 } else {
1087 SkPaint tmpPaint;
1088 tmpPaint.setAlpha(alpha);
1089 return this->saveLayer(bounds, &tmpPaint);
1090 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001091}
1092
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093void SkCanvas::internalRestore() {
1094 SkASSERT(fMCStack.count() != 0);
1095
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001096 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097 DeviceCM* layer = fMCRec->fLayer; // may be null
1098 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001099 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100
1101 // now do the normal restore()
1102 fMCRec->~MCRec(); // balanced in save()
1103 fMCStack.pop_back();
1104 fMCRec = (MCRec*)fMCStack.back();
1105
Mike Reedc42a1cd2017-02-14 14:25:14 -05001106 if (fMCRec) {
1107 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1108 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001109
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1111 since if we're being recorded, we don't want to record this (the
1112 recorder will have already recorded the restore).
1113 */
bsalomon49f085d2014-09-05 13:34:00 -07001114 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001115 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001116 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001117 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001118 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001119 layer->fPaint.get(),
1120 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001121 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001122 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001123 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001124 delete layer;
reedb679ca82015-04-07 04:40:48 -07001125 } else {
1126 // we're at the root
reeda499f902015-05-01 09:34:31 -07001127 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001128 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001129 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001130 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001131 }
msarettfbfa2582016-08-12 08:29:08 -07001132
1133 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001134 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001135 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1136 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137}
1138
reede8f30622016-03-23 18:59:25 -07001139sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001140 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001141 props = &fProps;
1142 }
1143 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001144}
1145
reede8f30622016-03-23 18:59:25 -07001146sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001147 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001148 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001149}
1150
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001151SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001152 return this->onImageInfo();
1153}
1154
1155SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001156 SkBaseDevice* dev = this->getDevice();
1157 if (dev) {
1158 return dev->imageInfo();
1159 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001160 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001161 }
1162}
1163
brianosman898235c2016-04-06 07:38:23 -07001164bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001165 return this->onGetProps(props);
1166}
1167
1168bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001169 SkBaseDevice* dev = this->getDevice();
1170 if (dev) {
1171 if (props) {
1172 *props = fProps;
1173 }
1174 return true;
1175 } else {
1176 return false;
1177 }
1178}
1179
reed6ceeebd2016-03-09 14:26:26 -08001180bool SkCanvas::peekPixels(SkPixmap* pmap) {
1181 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001182}
1183
reed884e97c2015-05-26 11:31:54 -07001184bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001185 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001186 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001187}
1188
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001189void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001190 SkPixmap pmap;
1191 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001192 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001193 }
1194 if (info) {
1195 *info = pmap.info();
1196 }
1197 if (rowBytes) {
1198 *rowBytes = pmap.rowBytes();
1199 }
1200 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001201 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001202 }
reed884e97c2015-05-26 11:31:54 -07001203 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001204}
1205
reed884e97c2015-05-26 11:31:54 -07001206bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001207 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001208 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001209}
1210
reed@android.com8a1c16f2008-12-17 15:59:43 +00001211/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212
Florin Malita53f77bd2017-04-28 13:48:37 -04001213void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1214 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001216 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217 paint = &tmp;
1218 }
reed@google.com4b226022011-01-11 18:32:13 +00001219
Ben Wagner2c312c42018-06-27 14:46:46 -04001220 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001221
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001223 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001224 paint = &looper.paint();
1225 SkImageFilter* filter = paint->getImageFilter();
1226 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001227 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001228 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1229 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001230 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1231 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001232 }
reed@google.com76dd2772012-01-05 21:15:07 +00001233 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001234 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001235 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236 }
reeda2217ef2016-07-20 06:04:34 -07001237
reed@google.com4e2b3d32011-04-07 14:18:59 +00001238 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239}
1240
reed32704672015-12-16 08:27:10 -08001241/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001242
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001243void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001244 if (dx || dy) {
1245 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001246 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001247
reedfe69b502016-09-12 06:31:48 -07001248 // Translate shouldn't affect the is-scale-translateness of the matrix.
1249 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001250
Mike Reedc42a1cd2017-02-14 14:25:14 -05001251 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001252
reedfe69b502016-09-12 06:31:48 -07001253 this->didTranslate(dx,dy);
1254 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255}
1256
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001257void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001258 SkMatrix m;
1259 m.setScale(sx, sy);
1260 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001261}
1262
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001263void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001264 SkMatrix m;
1265 m.setRotate(degrees);
1266 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001267}
1268
bungeman7438bfc2016-07-12 15:01:19 -07001269void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1270 SkMatrix m;
1271 m.setRotate(degrees, px, py);
1272 this->concat(m);
1273}
1274
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001275void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001276 SkMatrix m;
1277 m.setSkew(sx, sy);
1278 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001279}
1280
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001281void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001282 if (matrix.isIdentity()) {
1283 return;
1284 }
1285
reed2ff1fce2014-12-11 07:07:37 -08001286 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001287 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001288 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001289
Mike Reed7627fa52017-02-08 10:07:53 -05001290 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001291
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001292 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001293}
1294
reed8c30a812016-04-20 16:36:51 -07001295void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001296 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001297 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001298
Mike Reedc42a1cd2017-02-14 14:25:14 -05001299 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001300}
1301
1302void SkCanvas::setMatrix(const SkMatrix& matrix) {
1303 this->checkForDeferredSave();
1304 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001305 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306}
1307
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001309 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310}
1311
1312//////////////////////////////////////////////////////////////////////////////
1313
Mike Reedc1f77742016-12-09 09:00:50 -05001314void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001315 if (!rect.isFinite()) {
1316 return;
1317 }
reed2ff1fce2014-12-11 07:07:37 -08001318 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001319 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1320 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001321}
1322
Mike Reedc1f77742016-12-09 09:00:50 -05001323void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001324 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001325
Mike Reed7627fa52017-02-08 10:07:53 -05001326 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001327
reedc64eff52015-11-21 12:39:45 -08001328 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001329 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1330 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001331 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332}
1333
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001334void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1335 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001336 if (fClipRestrictionRect.isEmpty()) {
1337 // we notify the device, but we *dont* resolve deferred saves (since we're just
1338 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001339 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001340 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001341 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001342 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001343 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001344 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001345 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1346 }
1347}
1348
Mike Reedc1f77742016-12-09 09:00:50 -05001349void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001350 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001351 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001352 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001353 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1354 } else {
1355 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001356 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001357}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001358
Mike Reedc1f77742016-12-09 09:00:50 -05001359void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001360 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001361
Brian Salomona3b45d42016-10-03 11:36:16 -04001362 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001363
Mike Reed7627fa52017-02-08 10:07:53 -05001364 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001365
Mike Reed20800c82017-11-15 16:09:04 -05001366 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1367 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001368 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001369}
1370
Mike Reedc1f77742016-12-09 09:00:50 -05001371void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001372 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001373 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001374
1375 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1376 SkRect r;
1377 if (path.isRect(&r)) {
1378 this->onClipRect(r, op, edgeStyle);
1379 return;
1380 }
1381 SkRRect rrect;
1382 if (path.isOval(&r)) {
1383 rrect.setOval(r);
1384 this->onClipRRect(rrect, op, edgeStyle);
1385 return;
1386 }
1387 if (path.isRRect(&rrect)) {
1388 this->onClipRRect(rrect, op, edgeStyle);
1389 return;
1390 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001391 }
robertphillips39f05382015-11-24 09:30:12 -08001392
1393 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001394}
1395
Mike Reedc1f77742016-12-09 09:00:50 -05001396void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001397 AutoValidateClip avc(this);
1398
Brian Salomona3b45d42016-10-03 11:36:16 -04001399 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001400
Mike Reed7627fa52017-02-08 10:07:53 -05001401 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402
Brian Salomona3b45d42016-10-03 11:36:16 -04001403 const SkPath* rasterClipPath = &path;
1404 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001405 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1406 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001407 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408}
1409
Mike Reedc1f77742016-12-09 09:00:50 -05001410void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001411 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001412 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001413}
1414
Mike Reedc1f77742016-12-09 09:00:50 -05001415void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001416 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001417
reed@google.com5c3d1472011-02-22 19:12:23 +00001418 AutoValidateClip avc(this);
1419
Mike Reed20800c82017-11-15 16:09:04 -05001420 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001421 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422}
1423
reed@google.com819c9212011-02-23 18:56:55 +00001424#ifdef SK_DEBUG
1425void SkCanvas::validateClip() const {
1426 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001427 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001428 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001429 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001430 return;
1431 }
reed@google.com819c9212011-02-23 18:56:55 +00001432}
1433#endif
1434
Mike Reeda1361362017-03-07 09:37:29 -05001435bool SkCanvas::androidFramework_isClipAA() const {
1436 bool containsAA = false;
1437
1438 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1439
1440 return containsAA;
1441}
1442
1443class RgnAccumulator {
1444 SkRegion* fRgn;
1445public:
1446 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1447 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1448 SkIPoint origin = device->getOrigin();
1449 if (origin.x() | origin.y()) {
1450 rgn->translate(origin.x(), origin.y());
1451 }
1452 fRgn->op(*rgn, SkRegion::kUnion_Op);
1453 }
1454};
1455
1456void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1457 RgnAccumulator accum(rgn);
1458 SkRegion tmp;
1459
1460 rgn->setEmpty();
1461 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001462}
1463
reed@google.com5c3d1472011-02-22 19:12:23 +00001464///////////////////////////////////////////////////////////////////////////////
1465
reed@google.com754de5f2014-02-24 19:38:20 +00001466bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001467 return fMCRec->fRasterClip.isEmpty();
1468
1469 // TODO: should we only use the conservative answer in a recording canvas?
1470#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001471 SkBaseDevice* dev = this->getTopDevice();
1472 // if no device we return true
1473 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001474#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001475}
1476
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001477bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001478 SkBaseDevice* dev = this->getTopDevice();
1479 // if no device we return false
1480 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001481}
1482
msarettfbfa2582016-08-12 08:29:08 -07001483static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1484#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1485 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1486 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1487 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1488 return 0xF != _mm_movemask_ps(mask);
1489#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1490 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1491 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1492 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1493 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1494#else
1495 SkRect devRectAsRect;
1496 SkRect devClipAsRect;
1497 devRect.store(&devRectAsRect.fLeft);
1498 devClip.store(&devClipAsRect.fLeft);
1499 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1500#endif
1501}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001502
msarettfbfa2582016-08-12 08:29:08 -07001503// It's important for this function to not be inlined. Otherwise the compiler will share code
1504// between the fast path and the slow path, resulting in two slow paths.
1505static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1506 const SkMatrix& matrix) {
1507 SkRect deviceRect;
1508 matrix.mapRect(&deviceRect, src);
1509 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1510}
1511
1512bool SkCanvas::quickReject(const SkRect& src) const {
1513#ifdef SK_DEBUG
1514 // Verify that fDeviceClipBounds are set properly.
1515 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001516 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001517 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001518 } else {
msarettfbfa2582016-08-12 08:29:08 -07001519 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001520 }
msarettfbfa2582016-08-12 08:29:08 -07001521
msarett9637ea92016-08-18 14:03:30 -07001522 // Verify that fIsScaleTranslate is set properly.
1523 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001524#endif
1525
msarett9637ea92016-08-18 14:03:30 -07001526 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001527 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1528 }
1529
1530 // We inline the implementation of mapScaleTranslate() for the fast path.
1531 float sx = fMCRec->fMatrix.getScaleX();
1532 float sy = fMCRec->fMatrix.getScaleY();
1533 float tx = fMCRec->fMatrix.getTranslateX();
1534 float ty = fMCRec->fMatrix.getTranslateY();
1535 Sk4f scale(sx, sy, sx, sy);
1536 Sk4f trans(tx, ty, tx, ty);
1537
1538 // Apply matrix.
1539 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1540
1541 // Make sure left < right, top < bottom.
1542 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1543 Sk4f min = Sk4f::Min(ltrb, rblt);
1544 Sk4f max = Sk4f::Max(ltrb, rblt);
1545 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1546 // ARM this sequence generates the fastest (a single instruction).
1547 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1548
1549 // Check if the device rect is NaN or outside the clip.
1550 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001551}
1552
reed@google.com3b3e8952012-08-16 20:53:31 +00001553bool SkCanvas::quickReject(const SkPath& path) const {
1554 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001555}
1556
Mike Klein83c8dd92017-11-28 17:08:45 -05001557SkRect SkCanvas::getLocalClipBounds() const {
1558 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001559 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001560 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001561 }
1562
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001563 SkMatrix inverse;
1564 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001565 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001566 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001567 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001568
Mike Reed42e8c532017-01-23 14:09:13 -05001569 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001570 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001571 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001572
Mike Reedb57b9312018-04-23 12:12:54 -04001573 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001574 inverse.mapRect(&bounds, r);
1575 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001576}
1577
Mike Klein83c8dd92017-11-28 17:08:45 -05001578SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001579 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001580}
1581
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001583 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001584}
1585
Brian Osman11052242016-10-27 14:47:55 -04001586GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001587 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001588 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001589}
1590
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001591GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001592 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001593 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001594}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001595
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001596void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1597 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001598 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001599 if (outer.isEmpty()) {
1600 return;
1601 }
1602 if (inner.isEmpty()) {
1603 this->drawRRect(outer, paint);
1604 return;
1605 }
1606
1607 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001608 // be able to return ...
1609 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001610 //
1611 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001612 if (!outer.getBounds().contains(inner.getBounds())) {
1613 return;
1614 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001615
1616 this->onDrawDRRect(outer, inner, paint);
1617}
1618
reed41af9662015-01-05 07:49:08 -08001619void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001620 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001621 this->onDrawPaint(paint);
1622}
1623
1624void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001625 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001626 // To avoid redundant logic in our culling code and various backends, we always sort rects
1627 // before passing them along.
1628 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001629}
1630
msarettdca352e2016-08-26 06:37:45 -07001631void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001632 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001633 if (region.isEmpty()) {
1634 return;
1635 }
1636
1637 if (region.isRect()) {
1638 return this->drawIRect(region.getBounds(), paint);
1639 }
1640
1641 this->onDrawRegion(region, paint);
1642}
1643
reed41af9662015-01-05 07:49:08 -08001644void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001645 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001646 // To avoid redundant logic in our culling code and various backends, we always sort rects
1647 // before passing them along.
1648 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001649}
1650
1651void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001652 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001653 this->onDrawRRect(rrect, paint);
1654}
1655
1656void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001657 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001658 this->onDrawPoints(mode, count, pts, paint);
1659}
1660
Mike Reede88a1cb2017-03-17 09:50:46 -04001661void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1662 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001663 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001664 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001665 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1666 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001667 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001668}
1669
1670void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001671 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001672 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001673 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1674}
1675
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001676void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1677 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001678 TRACE_EVENT0("skia", TRACE_FUNC);
1679 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001680 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001681 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1682}
1683
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001684void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1685 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001686 TRACE_EVENT0("skia", TRACE_FUNC);
1687 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001688 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001689 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001690}
1691
1692void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001693 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001694 this->onDrawPath(path, paint);
1695}
1696
reeda85d4d02015-05-06 12:56:48 -07001697void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001698 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001699 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001700 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001701}
1702
Mike Reedc4e31092018-01-30 11:15:27 -05001703// Returns true if the rect can be "filled" : non-empty and finite
1704static bool fillable(const SkRect& r) {
1705 SkScalar w = r.width();
1706 SkScalar h = r.height();
1707 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1708}
1709
reede47829b2015-08-06 10:02:53 -07001710void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1711 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001712 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001713 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001714 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001715 return;
1716 }
1717 this->onDrawImageRect(image, &src, dst, paint, constraint);
1718}
reed41af9662015-01-05 07:49:08 -08001719
reed84984ef2015-07-17 07:09:43 -07001720void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1721 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001722 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001723 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001724}
1725
Brian Salomonf08002c2018-10-26 16:15:46 -04001726void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001727 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001728 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001729 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001730}
reede47829b2015-08-06 10:02:53 -07001731
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001732namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001733class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001734public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001735 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1736 if (!origPaint) {
1737 return;
1738 }
1739 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1740 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1741 }
1742 if (origPaint->getMaskFilter()) {
1743 fPaint.writable()->setMaskFilter(nullptr);
1744 }
1745 if (origPaint->isAntiAlias()) {
1746 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001747 }
1748 }
1749
1750 const SkPaint* get() const {
1751 return fPaint;
1752 }
1753
1754private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001755 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001756};
1757} // namespace
1758
reed4c21dc52015-06-25 12:32:03 -07001759void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1760 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001761 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001762 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001763 if (dst.isEmpty()) {
1764 return;
1765 }
msarett552bca92016-08-03 06:53:26 -07001766 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001767 LatticePaint latticePaint(paint);
1768 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001769 } else {
reede47829b2015-08-06 10:02:53 -07001770 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001771 }
reed4c21dc52015-06-25 12:32:03 -07001772}
1773
msarett16882062016-08-16 09:31:08 -07001774void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1775 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001776 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001777 RETURN_ON_NULL(image);
1778 if (dst.isEmpty()) {
1779 return;
1780 }
msarett71df2d72016-09-30 12:41:42 -07001781
1782 SkIRect bounds;
1783 Lattice latticePlusBounds = lattice;
1784 if (!latticePlusBounds.fBounds) {
1785 bounds = SkIRect::MakeWH(image->width(), image->height());
1786 latticePlusBounds.fBounds = &bounds;
1787 }
1788
1789 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001790 LatticePaint latticePaint(paint);
1791 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001792 } else {
1793 this->drawImageRect(image, dst, paint);
1794 }
1795}
1796
Brian Salomon1da5cad2018-11-21 09:21:18 -05001797void SkCanvas::experimental_DrawImageSetV1(const ImageSetEntry imageSet[], int cnt,
1798 SkFilterQuality filterQuality, SkBlendMode mode) {
1799 TRACE_EVENT0("skia", TRACE_FUNC);
1800 RETURN_ON_NULL(imageSet);
1801 RETURN_ON_FALSE(cnt);
1802
Brian Salomond003d222018-11-26 13:25:05 -05001803 this->onDrawImageSet(imageSet, cnt, filterQuality, mode);
Brian Salomon1da5cad2018-11-21 09:21:18 -05001804}
1805
reed41af9662015-01-05 07:49:08 -08001806void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001807 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001808 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001809 return;
1810 }
reed41af9662015-01-05 07:49:08 -08001811 this->onDrawBitmap(bitmap, dx, dy, paint);
1812}
1813
reede47829b2015-08-06 10:02:53 -07001814void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001815 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001816 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001817 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001818 return;
1819 }
reede47829b2015-08-06 10:02:53 -07001820 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001821}
1822
reed84984ef2015-07-17 07:09:43 -07001823void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1824 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001825 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001826}
1827
reede47829b2015-08-06 10:02:53 -07001828void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1829 SrcRectConstraint constraint) {
1830 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1831 constraint);
1832}
reede47829b2015-08-06 10:02:53 -07001833
reed41af9662015-01-05 07:49:08 -08001834void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1835 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001836 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001837 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001838 return;
1839 }
msarett552bca92016-08-03 06:53:26 -07001840 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001841 LatticePaint latticePaint(paint);
1842 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001843 } else {
reeda5517e22015-07-14 10:54:12 -07001844 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001845 }
reed41af9662015-01-05 07:49:08 -08001846}
1847
msarettc573a402016-08-02 08:05:56 -07001848void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1849 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001850 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001851 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001852 return;
1853 }
msarett71df2d72016-09-30 12:41:42 -07001854
1855 SkIRect bounds;
1856 Lattice latticePlusBounds = lattice;
1857 if (!latticePlusBounds.fBounds) {
1858 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1859 latticePlusBounds.fBounds = &bounds;
1860 }
1861
1862 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001863 LatticePaint latticePaint(paint);
1864 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001865 } else {
msarett16882062016-08-16 09:31:08 -07001866 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001867 }
msarettc573a402016-08-02 08:05:56 -07001868}
1869
reed71c3c762015-06-24 10:29:17 -07001870void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001871 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001872 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001873 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001874 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001875 if (count <= 0) {
1876 return;
1877 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001878 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001879 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001880 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001881}
1882
reedf70b5312016-03-04 16:36:20 -08001883void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001884 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001885 if (key) {
1886 this->onDrawAnnotation(rect, key, value);
1887 }
1888}
1889
reede47829b2015-08-06 10:02:53 -07001890void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1891 const SkPaint* paint, SrcRectConstraint constraint) {
1892 if (src) {
1893 this->drawImageRect(image, *src, dst, paint, constraint);
1894 } else {
1895 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1896 dst, paint, constraint);
1897 }
1898}
1899void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1900 const SkPaint* paint, SrcRectConstraint constraint) {
1901 if (src) {
1902 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1903 } else {
1904 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1905 dst, paint, constraint);
1906 }
1907}
1908
Mike Reed4204da22017-05-17 08:53:36 -04001909void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001910 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001911 this->onDrawShadowRec(path, rec);
1912}
1913
1914void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1915 SkPaint paint;
1916 const SkRect& pathBounds = path.getBounds();
1917
Ben Wagner2c312c42018-06-27 14:46:46 -04001918 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001919 while (iter.next()) {
1920 iter.fDevice->drawShadow(path, rec);
1921 }
1922 LOOPER_END
1923}
1924
reed@android.com8a1c16f2008-12-17 15:59:43 +00001925//////////////////////////////////////////////////////////////////////////////
1926// These are the virtual drawing methods
1927//////////////////////////////////////////////////////////////////////////////
1928
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001929void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001930 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001931 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1932 }
1933}
1934
reed41af9662015-01-05 07:49:08 -08001935void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001936 this->internalDrawPaint(paint);
1937}
1938
1939void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001940 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001941
1942 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001943 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001944 }
1945
reed@google.com4e2b3d32011-04-07 14:18:59 +00001946 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001947}
1948
reed41af9662015-01-05 07:49:08 -08001949void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1950 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001951 if ((long)count <= 0) {
1952 return;
1953 }
1954
Mike Reed822128b2017-02-28 16:41:03 -05001955 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001956 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001957 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001958 // special-case 2 points (common for drawing a single line)
1959 if (2 == count) {
1960 r.set(pts[0], pts[1]);
1961 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001962 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001963 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001964 if (!r.isFinite()) {
1965 return;
1966 }
Mike Reed822128b2017-02-28 16:41:03 -05001967 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001968 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1969 return;
1970 }
1971 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001972 }
reed@google.coma584aed2012-05-16 14:06:02 +00001973
halcanary96fcdcc2015-08-27 07:41:13 -07001974 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001975
Ben Wagner2c312c42018-06-27 14:46:46 -04001976 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001977
reed@android.com8a1c16f2008-12-17 15:59:43 +00001978 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001979 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001980 }
reed@google.com4b226022011-01-11 18:32:13 +00001981
reed@google.com4e2b3d32011-04-07 14:18:59 +00001982 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001983}
1984
reed4a167172016-08-18 17:15:25 -07001985static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1986 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07001987 (intptr_t)paint.getLooper() ) != 0;
1988}
1989
reed41af9662015-01-05 07:49:08 -08001990void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001991 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001992 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001993 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001994 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001995 return;
1996 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997 }
reed@google.com4b226022011-01-11 18:32:13 +00001998
reed4a167172016-08-18 17:15:25 -07001999 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002000 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002001
reed4a167172016-08-18 17:15:25 -07002002 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002003 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002004 }
2005
2006 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002007 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002008 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002009 SkDrawIter iter(this);
2010 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002011 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002012 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002013 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002014}
2015
msarett44df6512016-08-25 13:54:30 -07002016void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002017 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002018 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002019 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002020 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2021 return;
2022 }
msarett44df6512016-08-25 13:54:30 -07002023 }
2024
Ben Wagner2c312c42018-06-27 14:46:46 -04002025 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002026
2027 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002028 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002029 }
2030
2031 LOOPER_END
2032}
2033
reed41af9662015-01-05 07:49:08 -08002034void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002035 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002036 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002037 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002038 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002039 return;
2040 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002041 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002042
Ben Wagner2c312c42018-06-27 14:46:46 -04002043 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002044
2045 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002046 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002047 }
2048
2049 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002050}
2051
bsalomonac3aa242016-08-19 11:25:19 -07002052void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2053 SkScalar sweepAngle, bool useCenter,
2054 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002055 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002056 if (paint.canComputeFastBounds()) {
2057 SkRect storage;
2058 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002059 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002060 return;
2061 }
bsalomonac3aa242016-08-19 11:25:19 -07002062 }
2063
Ben Wagner2c312c42018-06-27 14:46:46 -04002064 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002065
2066 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002067 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002068 }
2069
2070 LOOPER_END
2071}
2072
reed41af9662015-01-05 07:49:08 -08002073void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002074 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002075 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002076 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2077 return;
2078 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002079 }
2080
2081 if (rrect.isRect()) {
2082 // call the non-virtual version
2083 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002084 return;
2085 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002086 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002087 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2088 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002089 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002090
Ben Wagner2c312c42018-06-27 14:46:46 -04002091 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002092
2093 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002094 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002095 }
2096
2097 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002098}
2099
Mike Reed822128b2017-02-28 16:41:03 -05002100void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002101 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002102 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002103 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2104 return;
2105 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002106 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002107
Ben Wagner2c312c42018-06-27 14:46:46 -04002108 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002109
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002110 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002111 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002112 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002113
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002114 LOOPER_END
2115}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002116
reed41af9662015-01-05 07:49:08 -08002117void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002118 if (!path.isFinite()) {
2119 return;
2120 }
2121
Mike Reed822128b2017-02-28 16:41:03 -05002122 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002123 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002124 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002125 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2126 return;
2127 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002128 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002129
Mike Reed822128b2017-02-28 16:41:03 -05002130 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002131 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002132 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002133 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002134 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002135 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002136
Ben Wagner2c312c42018-06-27 14:46:46 -04002137 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002138
2139 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002140 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002141 }
2142
reed@google.com4e2b3d32011-04-07 14:18:59 +00002143 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002144}
2145
reed262a71b2015-12-05 13:07:27 -08002146bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002147 if (!paint.getImageFilter()) {
2148 return false;
2149 }
2150
2151 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002152 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002153 return false;
2154 }
2155
2156 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2157 // Once we can filter and the filter will return a result larger than itself, we should be
2158 // able to remove this constraint.
2159 // skbug.com/4526
2160 //
2161 SkPoint pt;
2162 ctm.mapXY(x, y, &pt);
2163 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2164 return ir.contains(fMCRec->fRasterClip.getBounds());
2165}
2166
Mike Reedf441cfc2018-04-11 14:50:16 -04002167// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2168// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2169// null.
2170static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2171 if (paintParam) {
2172 *real = *paintParam;
2173 real->setStyle(SkPaint::kFill_Style);
2174 real->setPathEffect(nullptr);
2175 paintParam = real;
2176 }
2177 return paintParam;
2178}
2179
reeda85d4d02015-05-06 12:56:48 -07002180void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002181 SkPaint realPaint;
2182 paint = init_image_paint(&realPaint, paint);
2183
reeda85d4d02015-05-06 12:56:48 -07002184 SkRect bounds = SkRect::MakeXYWH(x, y,
2185 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002186 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002187 SkRect tmp = bounds;
2188 if (paint) {
2189 paint->computeFastBounds(tmp, &tmp);
2190 }
2191 if (this->quickReject(tmp)) {
2192 return;
2193 }
reeda85d4d02015-05-06 12:56:48 -07002194 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002195 // At this point we need a real paint object. If the caller passed null, then we should
2196 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2197 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2198 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002199
reeda2217ef2016-07-20 06:04:34 -07002200 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002201 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2202 *paint);
2203 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002204 special = this->getDevice()->makeSpecial(image);
2205 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002206 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002207 }
2208 }
2209
reed262a71b2015-12-05 13:07:27 -08002210 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2211
reeda85d4d02015-05-06 12:56:48 -07002212 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002213 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002214 if (special) {
2215 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002216 iter.fDevice->ctm().mapXY(x, y, &pt);
2217 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002218 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002219 SkScalarRoundToInt(pt.fY), pnt,
2220 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002221 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002222 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002223 }
reeda85d4d02015-05-06 12:56:48 -07002224 }
halcanary9d524f22016-03-29 09:03:52 -07002225
reeda85d4d02015-05-06 12:56:48 -07002226 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002227}
2228
reed41af9662015-01-05 07:49:08 -08002229void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002230 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002231 SkPaint realPaint;
2232 paint = init_image_paint(&realPaint, paint);
2233
halcanary96fcdcc2015-08-27 07:41:13 -07002234 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002235 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002236 if (paint) {
2237 paint->computeFastBounds(dst, &storage);
2238 }
2239 if (this->quickReject(storage)) {
2240 return;
2241 }
reeda85d4d02015-05-06 12:56:48 -07002242 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002243 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002244
Ben Wagner2c312c42018-06-27 14:46:46 -04002245 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002246
reeda85d4d02015-05-06 12:56:48 -07002247 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002248 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002249 }
halcanary9d524f22016-03-29 09:03:52 -07002250
reeda85d4d02015-05-06 12:56:48 -07002251 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002252}
2253
reed41af9662015-01-05 07:49:08 -08002254void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002255 SkDEBUGCODE(bitmap.validate();)
2256
reed33366972015-10-08 09:22:02 -07002257 if (bitmap.drawsNothing()) {
2258 return;
2259 }
2260
Mike Reedf441cfc2018-04-11 14:50:16 -04002261 SkPaint realPaint;
2262 init_image_paint(&realPaint, paint);
2263 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002264
Mike Reed822128b2017-02-28 16:41:03 -05002265 SkRect bounds;
2266 bitmap.getBounds(&bounds);
2267 bounds.offset(x, y);
2268 bool canFastBounds = paint->canComputeFastBounds();
2269 if (canFastBounds) {
2270 SkRect storage;
2271 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002272 return;
2273 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002274 }
reed@google.com4b226022011-01-11 18:32:13 +00002275
reeda2217ef2016-07-20 06:04:34 -07002276 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002277 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2278 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002279 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002280 special = this->getDevice()->makeSpecial(bitmap);
2281 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002282 drawAsSprite = false;
2283 }
2284 }
2285
Mike Reed822128b2017-02-28 16:41:03 -05002286 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002287
2288 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002289 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002290 if (special) {
reed262a71b2015-12-05 13:07:27 -08002291 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002292 iter.fDevice->ctm().mapXY(x, y, &pt);
2293 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002294 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002295 SkScalarRoundToInt(pt.fY), pnt,
2296 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002297 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002298 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002299 }
reed33366972015-10-08 09:22:02 -07002300 }
msarettfbfa2582016-08-12 08:29:08 -07002301
reed33366972015-10-08 09:22:02 -07002302 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002303}
2304
reed@google.com9987ec32011-09-07 11:57:52 +00002305// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002306void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002307 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002308 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002309 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002310 return;
2311 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002312
halcanary96fcdcc2015-08-27 07:41:13 -07002313 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002314 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002315 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2316 return;
2317 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318 }
reed@google.com3d608122011-11-21 15:16:16 +00002319
reed@google.com33535f32012-09-25 15:37:50 +00002320 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002321 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002322 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002323 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002324
Ben Wagner2c312c42018-06-27 14:46:46 -04002325 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002326
reed@google.com33535f32012-09-25 15:37:50 +00002327 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002328 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002329 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002330
reed@google.com33535f32012-09-25 15:37:50 +00002331 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002332}
2333
reed41af9662015-01-05 07:49:08 -08002334void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002335 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002336 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002337 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002338}
2339
reed4c21dc52015-06-25 12:32:03 -07002340void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2341 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002342 SkPaint realPaint;
2343 paint = init_image_paint(&realPaint, paint);
2344
halcanary96fcdcc2015-08-27 07:41:13 -07002345 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002346 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002347 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2348 return;
2349 }
reed@google.com3d608122011-11-21 15:16:16 +00002350 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002351 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002352
Ben Wagner2c312c42018-06-27 14:46:46 -04002353 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002354
reed4c21dc52015-06-25 12:32:03 -07002355 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002356 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002357 }
halcanary9d524f22016-03-29 09:03:52 -07002358
reed4c21dc52015-06-25 12:32:03 -07002359 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002360}
2361
reed41af9662015-01-05 07:49:08 -08002362void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2363 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002364 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002365 SkPaint realPaint;
2366 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002367
halcanary96fcdcc2015-08-27 07:41:13 -07002368 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002369 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002370 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2371 return;
2372 }
reed4c21dc52015-06-25 12:32:03 -07002373 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002374 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002375
Ben Wagner2c312c42018-06-27 14:46:46 -04002376 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002377
reed4c21dc52015-06-25 12:32:03 -07002378 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002379 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002380 }
halcanary9d524f22016-03-29 09:03:52 -07002381
reed4c21dc52015-06-25 12:32:03 -07002382 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002383}
2384
msarett16882062016-08-16 09:31:08 -07002385void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2386 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002387 SkPaint realPaint;
2388 paint = init_image_paint(&realPaint, paint);
2389
msarett16882062016-08-16 09:31:08 -07002390 if (nullptr == paint || paint->canComputeFastBounds()) {
2391 SkRect storage;
2392 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2393 return;
2394 }
2395 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002396 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002397
Ben Wagner2c312c42018-06-27 14:46:46 -04002398 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002399
2400 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002401 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002402 }
2403
2404 LOOPER_END
2405}
2406
Brian Salomond003d222018-11-26 13:25:05 -05002407void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count,
Brian Salomond7065e72018-10-12 11:42:02 -04002408 SkFilterQuality filterQuality, SkBlendMode mode) {
2409 SkPaint paint;
Brian Salomon23356442018-11-30 15:33:19 -05002410 LOOPER_BEGIN(paint, nullptr)
Brian Salomond7065e72018-10-12 11:42:02 -04002411 while (iter.next()) {
Brian Salomond003d222018-11-26 13:25:05 -05002412 iter.fDevice->drawImageSet(imageSet, count, filterQuality, mode);
Brian Salomond7065e72018-10-12 11:42:02 -04002413 }
2414 LOOPER_END
2415}
2416
msarett16882062016-08-16 09:31:08 -07002417void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2418 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002419 SkPaint realPaint;
2420 paint = init_image_paint(&realPaint, paint);
2421
msarett16882062016-08-16 09:31:08 -07002422 if (nullptr == paint || paint->canComputeFastBounds()) {
2423 SkRect storage;
2424 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2425 return;
2426 }
2427 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002428 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002429
Ben Wagner2c312c42018-06-27 14:46:46 -04002430 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002431
2432 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002433 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002434 }
2435
2436 LOOPER_END
2437}
2438
reed@google.come0d9ce82014-04-23 04:00:17 +00002439void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2440 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002441
Ben Wagner2c312c42018-06-27 14:46:46 -04002442 LOOPER_BEGIN(paint, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002443
2444 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002445 fScratchGlyphRunBuilder->drawText(
Herb Derby4a447432018-06-22 11:45:27 -04002446 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Herb Derby8a6348e2018-07-12 15:30:35 -04002447 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002448 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002449 }
2450
reed@google.com4e2b3d32011-04-07 14:18:59 +00002451 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002452}
2453
reed@google.come0d9ce82014-04-23 04:00:17 +00002454void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2455 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002456
Ben Wagner2c312c42018-06-27 14:46:46 -04002457 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002458
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002460 fScratchGlyphRunBuilder->drawPosText(looper.paint(), text, byteLength, pos);
Herb Derby8a6348e2018-07-12 15:30:35 -04002461 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002462 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002463 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002464
reed@google.com4e2b3d32011-04-07 14:18:59 +00002465 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466}
2467
reed@google.come0d9ce82014-04-23 04:00:17 +00002468void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2469 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002470
Ben Wagner2c312c42018-06-27 14:46:46 -04002471 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002472
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002474 fScratchGlyphRunBuilder->drawPosTextH(
Herb Derby4a447432018-06-22 11:45:27 -04002475 looper.paint(), text, byteLength, xpos, constY);
Herb Derby8a6348e2018-07-12 15:30:35 -04002476 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002477 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002479
reed@google.com4e2b3d32011-04-07 14:18:59 +00002480 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481}
2482
Herb Derby2eacff02018-07-18 13:41:15 -04002483void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[],
reed45561a02016-07-07 12:47:17 -07002484 const SkRect* cullRect, const SkPaint& paint) {
2485 if (cullRect && this->quickReject(*cullRect)) {
2486 return;
2487 }
2488
Ben Wagner2c312c42018-06-27 14:46:46 -04002489 LOOPER_BEGIN(paint, nullptr)
reed45561a02016-07-07 12:47:17 -07002490
2491 while (iter.next()) {
Herb Derby2eacff02018-07-18 13:41:15 -04002492 fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len);
2493 auto list = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb935cf82018-07-26 16:54:18 -04002494 if (!list.empty()) {
2495 auto glyphRun = list[0];
Herb Derby2eacff02018-07-18 13:41:15 -04002496 iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform);
2497 }
reed45561a02016-07-07 12:47:17 -07002498 }
2499
2500 LOOPER_END
2501}
2502
fmalita00d5c2c2014-08-21 08:53:26 -07002503void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2504 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002505 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002506 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002507 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002508 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002509 SkRect tmp;
2510 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2511 return;
2512 }
2513 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002514 }
2515
fmalita024f9962015-03-03 19:08:17 -08002516 // We cannot filter in the looper as we normally do, because the paint is
2517 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002518 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002519
fmalitaaa1b9122014-08-28 14:32:24 -07002520 while (iter.next()) {
Herb Derbyb983e6b2018-07-13 13:26:29 -04002521 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, SkPoint::Make(x, y));
2522 iter.fDevice->drawGlyphRunList(fScratchGlyphRunBuilder->useGlyphRunList());
fmalita00d5c2c2014-08-21 08:53:26 -07002523 }
2524
fmalitaaa1b9122014-08-28 14:32:24 -07002525 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002526}
2527
Cary Clark2a475ea2017-04-28 15:35:12 -04002528void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2529 this->drawText(string.c_str(), string.size(), x, y, paint);
2530}
2531
Mike Reed358fcad2018-11-23 15:27:51 -05002532// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002533void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002534 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2535 TRACE_EVENT0("skia", TRACE_FUNC);
2536 if (byteLength) {
2537 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
2538 SkPaint tmp(paint);
2539 font.LEGACY_applyToPaint(&tmp);
Mike Reed7d1eb332018-12-04 17:35:56 -05002540 tmp.setTextEncoding(encoding);
Mike Reed358fcad2018-11-23 15:27:51 -05002541 this->onDrawText(text, byteLength, x, y, tmp);
2542 }
2543}
reed@google.come0d9ce82014-04-23 04:00:17 +00002544void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2545 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002546 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002547 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002548 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002549 this->onDrawText(text, byteLength, x, y, paint);
2550 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002551}
2552void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2553 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002554 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002555 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002556 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002557 this->onDrawPosText(text, byteLength, pos, paint);
2558 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002559}
2560void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2561 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002562 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002563 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002564 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002565 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2566 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002567}
Mike Reed7c8d2e92018-08-27 16:38:05 -04002568
reed45561a02016-07-07 12:47:17 -07002569void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2570 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002571 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002572 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002573 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002574 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2575 }
2576}
fmalita00d5c2c2014-08-21 08:53:26 -07002577void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2578 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002579 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002580 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002581 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002582 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002583}
reed@google.come0d9ce82014-04-23 04:00:17 +00002584
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002585void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002586 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002587 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002588
2589 while (iter.next()) {
2590 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002591 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002592 }
2593
2594 LOOPER_END
2595}
2596
dandovb3c9d1c2014-08-12 08:34:29 -07002597void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002598 const SkPoint texCoords[4], SkBlendMode bmode,
2599 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002600 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002601 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002602 return;
2603 }
mtklein6cfa73a2014-08-13 13:33:49 -07002604
Mike Reedfaba3712016-11-03 14:45:31 -04002605 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002606}
2607
2608void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002609 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002610 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002611 // Since a patch is always within the convex hull of the control points, we discard it when its
2612 // bounding rectangle is completely outside the current clip.
2613 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002614 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002615 if (this->quickReject(bounds)) {
2616 return;
2617 }
mtklein6cfa73a2014-08-13 13:33:49 -07002618
Ben Wagner2c312c42018-06-27 14:46:46 -04002619 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002620
dandovecfff212014-08-04 10:02:00 -07002621 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002622 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002623 }
mtklein6cfa73a2014-08-13 13:33:49 -07002624
dandovecfff212014-08-04 10:02:00 -07002625 LOOPER_END
2626}
2627
reeda8db7282015-07-07 10:22:31 -07002628void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002629#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002630 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002631#endif
reede3b38ce2016-01-08 09:18:44 -08002632 RETURN_ON_NULL(dr);
2633 if (x || y) {
2634 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2635 this->onDrawDrawable(dr, &matrix);
2636 } else {
2637 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002638 }
2639}
2640
reeda8db7282015-07-07 10:22:31 -07002641void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002642#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002643 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002644#endif
reede3b38ce2016-01-08 09:18:44 -08002645 RETURN_ON_NULL(dr);
2646 if (matrix && matrix->isIdentity()) {
2647 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002648 }
reede3b38ce2016-01-08 09:18:44 -08002649 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002650}
2651
2652void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002653 // drawable bounds are no longer reliable (e.g. android displaylist)
2654 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002655 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002656}
2657
reed71c3c762015-06-24 10:29:17 -07002658void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002659 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002660 const SkRect* cull, const SkPaint* paint) {
2661 if (cull && this->quickReject(*cull)) {
2662 return;
2663 }
2664
2665 SkPaint pnt;
2666 if (paint) {
2667 pnt = *paint;
2668 }
halcanary9d524f22016-03-29 09:03:52 -07002669
Ben Wagner2c312c42018-06-27 14:46:46 -04002670 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002671 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002672 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002673 }
2674 LOOPER_END
2675}
2676
reedf70b5312016-03-04 16:36:20 -08002677void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2678 SkASSERT(key);
2679
2680 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002681 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002682 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002683 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002684 }
2685 LOOPER_END
2686}
2687
reed@android.com8a1c16f2008-12-17 15:59:43 +00002688//////////////////////////////////////////////////////////////////////////////
2689// These methods are NOT virtual, and therefore must call back into virtual
2690// methods, rather than actually drawing themselves.
2691//////////////////////////////////////////////////////////////////////////////
2692
reed374772b2016-10-05 17:33:02 -07002693void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002694 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002695 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002696 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 this->drawPaint(paint);
2698}
2699
2700void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002701 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2703}
2704
Mike Reed3661bc92017-02-22 13:21:42 -05002705void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002706 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002707 pts[0].set(x0, y0);
2708 pts[1].set(x1, y1);
2709 this->drawPoints(kLines_PointMode, 2, pts, paint);
2710}
2711
Mike Reed3661bc92017-02-22 13:21:42 -05002712void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002713 if (radius < 0) {
2714 radius = 0;
2715 }
2716
2717 SkRect r;
2718 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002719 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002720}
2721
2722void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2723 const SkPaint& paint) {
2724 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002725 SkRRect rrect;
2726 rrect.setRectXY(r, rx, ry);
2727 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728 } else {
2729 this->drawRect(r, paint);
2730 }
2731}
2732
reed@android.com8a1c16f2008-12-17 15:59:43 +00002733void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2734 SkScalar sweepAngle, bool useCenter,
2735 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002736 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002737 if (oval.isEmpty() || !sweepAngle) {
2738 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002739 }
bsalomon21af9ca2016-08-25 12:29:23 -07002740 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741}
2742
reed@android.comf76bacf2009-05-13 14:00:33 +00002743///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002744#ifdef SK_DISABLE_SKPICTURE
2745void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002746
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002747
2748void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2749 const SkPaint* paint) {}
2750#else
Mike Klein88d90712018-01-27 17:30:04 +00002751/**
2752 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2753 * against the playback cost of recursing into the subpicture to get at its actual ops.
2754 *
2755 * For now we pick a conservatively small value, though measurement (and other heuristics like
2756 * the type of ops contained) may justify changing this value.
2757 */
2758#define kMaxPictureOpsToUnrollInsteadOfRef 1
2759
reedd5fa1a42014-08-09 11:08:05 -07002760void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002761 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002762 RETURN_ON_NULL(picture);
2763
reede3b38ce2016-01-08 09:18:44 -08002764 if (matrix && matrix->isIdentity()) {
2765 matrix = nullptr;
2766 }
Mike Klein88d90712018-01-27 17:30:04 +00002767 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2768 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2769 picture->playback(this);
2770 } else {
2771 this->onDrawPicture(picture, matrix, paint);
2772 }
reedd5fa1a42014-08-09 11:08:05 -07002773}
robertphillips9b14f262014-06-04 05:40:44 -07002774
reedd5fa1a42014-08-09 11:08:05 -07002775void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2776 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002777 if (!paint || paint->canComputeFastBounds()) {
2778 SkRect bounds = picture->cullRect();
2779 if (paint) {
2780 paint->computeFastBounds(bounds, &bounds);
2781 }
2782 if (matrix) {
2783 matrix->mapRect(&bounds);
2784 }
2785 if (this->quickReject(bounds)) {
2786 return;
2787 }
2788 }
2789
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002790 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002791 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002792}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002793#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795///////////////////////////////////////////////////////////////////////////////
2796///////////////////////////////////////////////////////////////////////////////
2797
reed3aafe112016-08-18 12:45:34 -07002798SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002799 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002800
2801 SkASSERT(canvas);
2802
reed3aafe112016-08-18 12:45:34 -07002803 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002804 fDone = !fImpl->next();
2805}
2806
2807SkCanvas::LayerIter::~LayerIter() {
2808 fImpl->~SkDrawIter();
2809}
2810
2811void SkCanvas::LayerIter::next() {
2812 fDone = !fImpl->next();
2813}
2814
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002815SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002816 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817}
2818
2819const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002820 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002821}
2822
2823const SkPaint& SkCanvas::LayerIter::paint() const {
2824 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002825 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826 paint = &fDefaultPaint;
2827 }
2828 return *paint;
2829}
2830
Mike Reedca37f322018-03-08 13:22:16 -05002831SkIRect SkCanvas::LayerIter::clipBounds() const {
2832 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002833}
2834
reed@android.com8a1c16f2008-12-17 15:59:43 +00002835int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2836int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002837
2838///////////////////////////////////////////////////////////////////////////////
2839
Mike Reed5df49342016-11-12 08:06:55 -06002840std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002841 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002842 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002843 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002844 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002845
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002846 SkBitmap bitmap;
2847 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002848 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002849 }
Mike Reed12f77342017-11-08 11:19:52 -05002850
2851 return props ?
2852 skstd::make_unique<SkCanvas>(bitmap, *props) :
2853 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002854}
reedd5fa1a42014-08-09 11:08:05 -07002855
2856///////////////////////////////////////////////////////////////////////////////
2857
Florin Malitaee424ac2016-12-01 12:47:59 -05002858SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002859 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002860
Florin Malita439ace92016-12-02 12:05:41 -05002861SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002862 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002863
Herb Derbyefe39bc2018-05-01 17:06:20 -04002864SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002865 : INHERITED(device) {}
2866
Florin Malitaee424ac2016-12-01 12:47:59 -05002867SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2868 (void)this->INHERITED::getSaveLayerStrategy(rec);
2869 return kNoLayer_SaveLayerStrategy;
2870}
2871
2872///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002873
reed73603f32016-09-20 08:42:38 -07002874static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2875static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2876static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2877static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2878static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2879static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002880
2881///////////////////////////////////////////////////////////////////////////////////////////////////
2882
2883SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2884 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002885 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002886 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2887 SkIPoint origin = dev->getOrigin();
2888 SkMatrix ctm = this->getTotalMatrix();
2889 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2890
2891 SkIRect clip = fMCRec->fRasterClip.getBounds();
2892 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002893 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002894 clip.setEmpty();
2895 }
2896
2897 fAllocator->updateHandle(handle, ctm, clip);
2898 return handle;
2899 }
2900 return nullptr;
2901}
2902
2903static bool install(SkBitmap* bm, const SkImageInfo& info,
2904 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002905 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002906}
2907
2908SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2909 SkBitmap* bm) {
2910 SkRasterHandleAllocator::Rec rec;
2911 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2912 return nullptr;
2913 }
2914 return rec.fHandle;
2915}
2916
2917std::unique_ptr<SkCanvas>
2918SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2919 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002920 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002921 return nullptr;
2922 }
2923
2924 SkBitmap bm;
2925 Handle hndl;
2926
2927 if (rec) {
2928 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2929 } else {
2930 hndl = alloc->allocBitmap(info, &bm);
2931 }
2932 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2933}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002934
2935///////////////////////////////////////////////////////////////////////////////////////////////////
2936
2937