blob: 4a6251f1104ba6fa9ff4dbc1e0c368788ab438e3 [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
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#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"
reed262a71b2015-12-05 13:07:27 -080021#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070022#include "SkImageFilter.h"
23#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070024#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060025#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080026#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000027#include "SkMetaData.h"
Ben Wagner4bd3b092017-08-01 13:22:23 -040028#include "SkMSAN.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"
reed@google.com00177082011-10-12 14:34:30 +000035#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050036#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000037#include "SkRRect.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"
fmalita7ba7aa72014-08-29 09:46:36 -070042#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000043#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000044#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080045#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070046#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000047
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080049#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050050#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070051
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050053#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050054#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000055
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:
reed1f836ee2014-07-07 07:49:34 -0700220 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700221 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 /* If there are any layers in the stack, this points to the top-most
223 one that is at or below this level in the stack (so we know what
224 bitmap/device to draw into from this level. This value is NOT
225 reference counted, since the real owner is either our fLayer field,
226 or a previous one in a lower level.)
227 */
Mike Reeda1361362017-03-07 09:37:29 -0500228 DeviceCM* fTopLayer;
229 SkConservativeClip fRasterClip;
230 SkMatrix fMatrix;
231 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232
Mike Reeda1361362017-03-07 09:37:29 -0500233 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700234 fFilter = nullptr;
235 fLayer = nullptr;
236 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800237 fMatrix.reset();
238 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700239
reedd9544982014-09-09 18:46:22 -0700240 // don't bother initializing fNext
241 inc_rec();
242 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400243 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700244 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700245 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700246 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800247 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700248
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249 // don't bother initializing fNext
250 inc_rec();
251 }
252 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000253 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700254 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 dec_rec();
256 }
mtkleinfeaadee2015-04-08 11:25:48 -0700257
258 void reset(const SkIRect& bounds) {
259 SkASSERT(fLayer);
260 SkASSERT(fDeferredSaveCount == 0);
261
262 fMatrix.reset();
263 fRasterClip.setRect(bounds);
264 fLayer->reset(bounds);
265 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266};
267
Mike Reeda1361362017-03-07 09:37:29 -0500268class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000269public:
Mike Reeda1361362017-03-07 09:37:29 -0500270 SkDrawIter(SkCanvas* canvas)
271 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
272 {}
reed@google.com4b226022011-01-11 18:32:13 +0000273
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000275 const DeviceCM* rec = fCurrLayer;
276 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400277 fDevice = rec->fDevice.get();
278 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700280 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 return true;
282 }
283 return false;
284 }
reed@google.com4b226022011-01-11 18:32:13 +0000285
reed@google.com6f8f2922011-03-04 22:27:10 +0000286 int getX() const { return fDevice->getOrigin().x(); }
287 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000289
Mike Reed99330ba2017-02-22 11:01:08 -0500290 SkBaseDevice* fDevice;
291
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293 const DeviceCM* fCurrLayer;
294 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295};
296
Florin Malita713b8ef2017-04-28 10:57:24 -0400297#define FOR_EACH_TOP_DEVICE( code ) \
298 do { \
299 DeviceCM* layer = fMCRec->fTopLayer; \
300 while (layer) { \
301 SkBaseDevice* device = layer->fDevice.get(); \
302 if (device) { \
303 code; \
304 } \
305 layer = layer->fNext; \
306 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500307 } while (0)
308
reed@android.com8a1c16f2008-12-17 15:59:43 +0000309/////////////////////////////////////////////////////////////////////////////
310
reeddbc3cef2015-04-29 12:18:57 -0700311static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
312 return lazy->isValid() ? lazy->get() : lazy->set(orig);
313}
314
315/**
316 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700317 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700318 */
reedd053ce92016-03-22 10:17:23 -0700319static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700320 SkImageFilter* imgf = paint.getImageFilter();
321 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700322 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700323 }
324
reedd053ce92016-03-22 10:17:23 -0700325 SkColorFilter* imgCFPtr;
326 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700327 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700328 }
reedd053ce92016-03-22 10:17:23 -0700329 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700330
331 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700332 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700333 // there is no existing paint colorfilter, so we can just return the imagefilter's
334 return imgCF;
335 }
336
337 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
338 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500339 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700340}
341
senorblanco87e066e2015-10-28 11:23:36 -0700342/**
343 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
344 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
345 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
346 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
347 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
348 * conservative "effective" bounds based on the settings in the paint... with one exception. This
349 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
350 * deliberately ignored.
351 */
352static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
353 const SkRect& rawBounds,
354 SkRect* storage) {
355 SkPaint tmpUnfiltered(paint);
356 tmpUnfiltered.setImageFilter(nullptr);
357 if (tmpUnfiltered.canComputeFastBounds()) {
358 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
359 } else {
360 return rawBounds;
361 }
362}
363
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364class AutoDrawLooper {
365public:
senorblanco87e066e2015-10-28 11:23:36 -0700366 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
367 // paint. It's used to determine the size of the offscreen layer for filters.
368 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700369 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700370 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000371 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800372#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800374#else
375 fFilter = nullptr;
376#endif
reed4a8126e2014-09-22 07:29:03 -0700377 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000378 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700379 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000380 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381
reedd053ce92016-03-22 10:17:23 -0700382 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700383 if (simplifiedCF) {
384 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700385 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700386 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700387 fPaint = paint;
388 }
389
390 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700391 /**
392 * We implement ImageFilters for a given draw by creating a layer, then applying the
393 * imagefilter to the pixels of that layer (its backing surface/image), and then
394 * we call restore() to xfer that layer to the main canvas.
395 *
396 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
397 * 2. Generate the src pixels:
398 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
399 * return (fPaint). We then draw the primitive (using srcover) into a cleared
400 * buffer/surface.
401 * 3. Restore the layer created in #1
402 * The imagefilter is passed the buffer/surface from the layer (now filled with the
403 * src pixels of the primitive). It returns a new "filtered" buffer, which we
404 * draw onto the previous layer using the xfermode from the original paint.
405 */
reed@google.com8926b162012-03-23 15:36:36 +0000406 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500407 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700408 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700409 SkRect storage;
410 if (rawBounds) {
411 // Make rawBounds include all paint outsets except for those due to image filters.
412 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
413 }
reedbfd5f172016-01-07 11:28:08 -0800414 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700415 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700416 fTempLayerForImageFilter = true;
417 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000418 }
419
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000420 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500421 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000422 fIsSimple = false;
423 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700424 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000425 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700426 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000427 }
428 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000429
reed@android.com8a1c16f2008-12-17 15:59:43 +0000430 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700431 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000432 fCanvas->internalRestore();
433 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000434 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000436
reed@google.com4e2b3d32011-04-07 14:18:59 +0000437 const SkPaint& paint() const {
438 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400439 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000440 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000442
reed@google.com129ec222012-05-15 13:24:09 +0000443 bool next(SkDrawFilter::Type drawType) {
444 if (fDone) {
445 return false;
446 } else if (fIsSimple) {
447 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000448 return !fPaint->nothingToDraw();
449 } else {
450 return this->doNext(drawType);
451 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000452 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000453
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500455 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700456 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000457 SkCanvas* fCanvas;
458 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000459 SkDrawFilter* fFilter;
460 const SkPaint* fPaint;
461 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700462 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000463 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000464 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000465 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400466 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000467
468 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000469};
470
reed@google.com129ec222012-05-15 13:24:09 +0000471bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700472 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000473 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700474 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000475
reeddbc3cef2015-04-29 12:18:57 -0700476 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
477 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400478 // never want our downstream clients (i.e. devices) to see loopers
479 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000480
reed5c476fb2015-04-20 08:04:21 -0700481 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700482 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700483 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000484 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000485
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000486 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000487 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000488 return false;
489 }
490 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000491 if (!fFilter->filter(paint, drawType)) {
492 fDone = true;
Mike Reed59af19f2018-04-12 17:26:40 -0400493 return false; // can we really do this, if we haven't finished fLooperContext?
reed@google.com971aca72012-11-26 20:26:54 +0000494 }
halcanary96fcdcc2015-08-27 07:41:13 -0700495 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000496 // no looper means we only draw once
497 fDone = true;
498 }
499 }
500 fPaint = paint;
501
502 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000503 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000504 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000505 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000506 return true;
507}
508
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509////////// macros to place around the internal draw calls //////////////////
510
reed3aafe112016-08-18 12:45:34 -0700511#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
512 this->predrawNotify(); \
513 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
514 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800515 SkDrawIter iter(this);
516
517
reed@google.com8926b162012-03-23 15:36:36 +0000518#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000519 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700520 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000521 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000522 SkDrawIter iter(this);
523
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000524#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000525 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700526 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000527 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000529
reedc83a2972015-07-16 07:40:45 -0700530#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
531 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700532 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700533 while (looper.next(type)) { \
534 SkDrawIter iter(this);
535
reed@google.com4e2b3d32011-04-07 14:18:59 +0000536#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537
538////////////////////////////////////////////////////////////////////////////
539
msarettfbfa2582016-08-12 08:29:08 -0700540static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
541 if (bounds.isEmpty()) {
542 return SkRect::MakeEmpty();
543 }
544
545 // Expand bounds out by 1 in case we are anti-aliasing. We store the
546 // bounds as floats to enable a faster quick reject implementation.
547 SkRect dst;
548 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
549 return dst;
550}
551
mtkleinfeaadee2015-04-08 11:25:48 -0700552void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
553 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700554 fMCRec->reset(bounds);
555
556 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500557 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400558 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700559 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700560 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700561}
562
Herb Derbyefe39bc2018-05-01 17:06:20 -0400563void SkCanvas::init(sk_sp<SkBaseDevice> device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800564 if (device && device->forceConservativeRasterClip()) {
565 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
566 }
reed42b73eb2015-11-20 13:42:42 -0800567
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000568 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800569 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700570 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571
572 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500573 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500574 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700575 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576
reeda499f902015-05-01 09:34:31 -0700577 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
578 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400579 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700580
reed@android.com8a1c16f2008-12-17 15:59:43 +0000581 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000582
halcanary96fcdcc2015-08-27 07:41:13 -0700583 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000584
reedf92c8662014-08-18 08:02:43 -0700585 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700586 // The root device and the canvas should always have the same pixel geometry
587 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800588 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700589 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500590
Mike Reedc42a1cd2017-02-14 14:25:14 -0500591 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700592 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400593
594 fScratchGlyphSet = skstd::make_unique<SkGlyphSet>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595}
596
reed@google.comcde92112011-07-06 20:00:52 +0000597SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000598 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700599 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000600{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000601 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000602
halcanary96fcdcc2015-08-27 07:41:13 -0700603 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000604}
605
reed96a857e2015-01-25 10:33:58 -0800606SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000607 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800608 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000609{
610 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400611 this->init(sk_make_sp<SkNoPixelsDevice>(
612 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps), kDefault_InitFlags);
reedd9544982014-09-09 18:46:22 -0700613}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000614
reed78e27682014-11-19 08:04:34 -0800615SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700616 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700617 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700618{
619 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700620
Mike Reed566e53c2017-03-10 10:49:45 -0500621 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400622 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps), flags);
reedd9544982014-09-09 18:46:22 -0700623}
624
Herb Derbyefe39bc2018-05-01 17:06:20 -0400625SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000626 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700627 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000628{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700630
reedd9544982014-09-09 18:46:22 -0700631 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632}
633
Herb Derbyefe39bc2018-05-01 17:06:20 -0400634SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device, InitFlags flags)
robertphillipsfcf78292015-06-19 11:49:52 -0700635 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700636 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700637{
638 inc_canvas();
639
640 this->init(device, flags);
641}
642
reed4a8126e2014-09-22 07:29:03 -0700643SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700644 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700645 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700646{
647 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700648
Mike Reed910ca0f2018-04-25 13:04:05 -0400649 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400650 this->init(device, kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700651}
reed29c857d2014-09-21 10:25:07 -0700652
Mike Reed356f7c22017-01-10 11:58:39 -0500653SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
654 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700655 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
656 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500657 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700658{
659 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700660
Mike Reed910ca0f2018-04-25 13:04:05 -0400661 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400662 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663}
664
Mike Reed356f7c22017-01-10 11:58:39 -0500665SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
666
Matt Sarett31f99ce2017-04-11 08:46:01 -0400667#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
668SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
669 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
670 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
671 , fAllocator(nullptr)
672{
673 inc_canvas();
674
675 SkBitmap tmp(bitmap);
676 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400677 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400678 this->init(device, kDefault_InitFlags);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400679}
680#endif
681
reed@android.com8a1c16f2008-12-17 15:59:43 +0000682SkCanvas::~SkCanvas() {
683 // free up the contents of our deque
684 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000685
reed@android.com8a1c16f2008-12-17 15:59:43 +0000686 this->internalRestore(); // restore the last, since we're going away
687
halcanary385fe4d2015-08-26 13:07:48 -0700688 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000689
reed@android.com8a1c16f2008-12-17 15:59:43 +0000690 dec_canvas();
691}
692
fmalita53d9f1c2016-01-25 06:23:54 -0800693#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000694SkDrawFilter* SkCanvas::getDrawFilter() const {
695 return fMCRec->fFilter;
696}
697
698SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700699 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000700 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
701 return filter;
702}
fmalita77650002016-01-21 18:47:11 -0800703#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000704
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000705SkMetaData& SkCanvas::getMetaData() {
706 // metadata users are rare, so we lazily allocate it. If that changes we
707 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700708 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000709 fMetaData = new SkMetaData;
710 }
711 return *fMetaData;
712}
713
reed@android.com8a1c16f2008-12-17 15:59:43 +0000714///////////////////////////////////////////////////////////////////////////////
715
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000716void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700717 this->onFlush();
718}
719
720void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000721 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000722 if (device) {
723 device->flush();
724 }
725}
726
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000727SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000728 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000729 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
730}
731
senorblancoafc7cce2016-02-02 18:44:15 -0800732SkIRect SkCanvas::getTopLayerBounds() const {
733 SkBaseDevice* d = this->getTopDevice();
734 if (!d) {
735 return SkIRect::MakeEmpty();
736 }
737 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
738}
739
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000740SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000741 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000742 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000743 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400744 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000745}
746
Florin Malita0ed3b642017-01-13 16:56:38 +0000747SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400748 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000749}
750
Mike Reed353196f2017-07-21 11:01:18 -0400751bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000752 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400753 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000754}
755
Mike Reed353196f2017-07-21 11:01:18 -0400756bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
757 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400758}
759
760bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
761 SkPixmap pm;
762 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
763}
764
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000765bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400766 SkPixmap pm;
767 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700768 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000769 }
770 return false;
771}
772
Matt Sarett03dd6d52017-01-23 12:15:09 -0500773bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000774 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000775 SkBaseDevice* device = this->getDevice();
776 if (!device) {
777 return false;
778 }
779
Matt Sarett03dd6d52017-01-23 12:15:09 -0500780 // This check gives us an early out and prevents generation ID churn on the surface.
781 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
782 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
783 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
784 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000785 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000786
Matt Sarett03dd6d52017-01-23 12:15:09 -0500787 // Tell our owning surface to bump its generation ID.
788 const bool completeOverwrite =
789 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700790 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700791
Matt Sarett03dd6d52017-01-23 12:15:09 -0500792 // This can still fail, most notably in the case of a invalid color type or alpha type
793 // conversion. We could pull those checks into this function and avoid the unnecessary
794 // generation ID bump. But then we would be performing those checks twice, since they
795 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400796 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000797}
reed@google.com51df9e32010-12-23 19:29:18 +0000798
reed@android.com8a1c16f2008-12-17 15:59:43 +0000799//////////////////////////////////////////////////////////////////////////////
800
reed2ff1fce2014-12-11 07:07:37 -0800801void SkCanvas::checkForDeferredSave() {
802 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800803 this->doSave();
804 }
805}
806
reedf0090cb2014-11-26 08:55:51 -0800807int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800808#ifdef SK_DEBUG
809 int count = 0;
810 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
811 for (;;) {
812 const MCRec* rec = (const MCRec*)iter.next();
813 if (!rec) {
814 break;
815 }
816 count += 1 + rec->fDeferredSaveCount;
817 }
818 SkASSERT(count == fSaveCount);
819#endif
820 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800821}
822
823int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800824 fSaveCount += 1;
825 fMCRec->fDeferredSaveCount += 1;
826 return this->getSaveCount() - 1; // return our prev value
827}
828
829void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800830 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700831
832 SkASSERT(fMCRec->fDeferredSaveCount > 0);
833 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800834 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800835}
836
837void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800838 if (fMCRec->fDeferredSaveCount > 0) {
839 SkASSERT(fSaveCount > 1);
840 fSaveCount -= 1;
841 fMCRec->fDeferredSaveCount -= 1;
842 } else {
843 // check for underflow
844 if (fMCStack.count() > 1) {
845 this->willRestore();
846 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700847 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800848 this->internalRestore();
849 this->didRestore();
850 }
reedf0090cb2014-11-26 08:55:51 -0800851 }
852}
853
854void SkCanvas::restoreToCount(int count) {
855 // sanity check
856 if (count < 1) {
857 count = 1;
858 }
mtkleinf0f14112014-12-12 08:46:25 -0800859
reedf0090cb2014-11-26 08:55:51 -0800860 int n = this->getSaveCount() - count;
861 for (int i = 0; i < n; ++i) {
862 this->restore();
863 }
864}
865
reed2ff1fce2014-12-11 07:07:37 -0800866void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700868 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000869 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000870
Mike Reedc42a1cd2017-02-14 14:25:14 -0500871 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872}
873
reed4960eee2015-12-18 07:09:18 -0800874bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400875 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000876}
877
reed4960eee2015-12-18 07:09:18 -0800878bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700879 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500880 SkIRect clipBounds = this->getDeviceClipBounds();
881 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000882 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000883 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000884
reed96e657d2015-03-10 17:30:07 -0700885 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
886
Robert Phillips12078432018-05-17 11:17:39 -0400887 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
888 // If the image filter DAG affects transparent black then we will need to render
889 // out to the clip bounds
890 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000891 }
Robert Phillips12078432018-05-17 11:17:39 -0400892
893 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700894 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000895 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700896 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400897 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000898 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400899 inputSaveLayerBounds = clipBounds;
900 }
901
902 if (imageFilter) {
903 // expand the clip bounds by the image filter DAG to include extra content that might
904 // be required by the image filters.
905 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
906 SkImageFilter::kReverse_MapDirection,
907 &inputSaveLayerBounds);
908 }
909
910 SkIRect clippedSaveLayerBounds;
911 if (bounds) {
912 // For better or for worse, user bounds currently act as a hard clip on the layer's
913 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
914 clippedSaveLayerBounds = inputSaveLayerBounds;
915 } else {
916 // If there are no user bounds, we don't want to artificially restrict the resulting
917 // layer bounds, so allow the expanded clip bounds free reign.
918 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800920
921 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400922 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800923 if (BoundsAffectsClip(saveLayerFlags)) {
924 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
925 fMCRec->fRasterClip.setEmpty();
926 fDeviceClipBounds.setEmpty();
927 }
928 return false;
929 }
Robert Phillips12078432018-05-17 11:17:39 -0400930 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000931
reed4960eee2015-12-18 07:09:18 -0800932 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700933 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400934 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
935 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000936 }
937
938 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400939 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000940 }
Robert Phillips12078432018-05-17 11:17:39 -0400941
junov@chromium.orga907ac32012-02-24 21:54:07 +0000942 return true;
943}
944
reed4960eee2015-12-18 07:09:18 -0800945int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
946 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000947}
948
reed70ee31b2015-12-10 13:44:45 -0800949int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800950 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
951}
952
Cary Clarke041e312018-03-06 13:00:52 -0500953int SkCanvas::saveLayer(const SaveLayerRec& rec) {
954 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
reed4960eee2015-12-18 07:09:18 -0800955 fSaveCount += 1;
Cary Clarke041e312018-03-06 13:00:52 -0500956 this->internalSaveLayer(rec, strategy);
reed4960eee2015-12-18 07:09:18 -0800957 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800958}
959
reeda2217ef2016-07-20 06:04:34 -0700960void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500961 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500962 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700963 SkDraw draw;
964 SkRasterClip rc;
965 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
966 if (!dst->accessPixels(&draw.fDst)) {
967 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800968 }
reeda2217ef2016-07-20 06:04:34 -0700969 draw.fMatrix = &SkMatrix::I();
970 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800971
972 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500973 if (filter) {
974 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
975 }
reeda2217ef2016-07-20 06:04:34 -0700976
Mike Reedc42a1cd2017-02-14 14:25:14 -0500977 int x = src->getOrigin().x() - dstOrigin.x();
978 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700979 auto special = src->snapSpecial();
980 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400981 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700982 }
robertphillips7354a4b2015-12-16 05:08:27 -0800983}
reed70ee31b2015-12-10 13:44:45 -0800984
Mike Kleine083f7c2018-02-07 12:54:27 -0500985static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500986 // Need to force L32 for now if we have an image filter.
987 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
988 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500989 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800990 }
Mike Klein649fb732018-02-26 15:09:16 -0500991
992 SkColorType ct = prev.colorType();
993 if (prev.bytesPerPixel() <= 4) {
994 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
995 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
996 ct = kN32_SkColorType;
997 }
998 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800999}
1000
reed4960eee2015-12-18 07:09:18 -08001001void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1002 const SkRect* bounds = rec.fBounds;
1003 const SkPaint* paint = rec.fPaint;
1004 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1005
reed8c30a812016-04-20 16:36:51 -07001006 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001007 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001008 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -04001009 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -07001010 SkMatrix remainder;
1011 SkSize scale;
1012 /*
1013 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1014 * but they do handle scaling. To accommodate this, we do the following:
1015 *
1016 * 1. Stash off the current CTM
1017 * 2. Decompose the CTM into SCALE and REMAINDER
1018 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1019 * contains the REMAINDER
1020 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1021 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1022 * of the original imagefilter, and draw that (via drawSprite)
1023 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1024 *
1025 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1026 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1027 */
reed96a04f32016-04-25 09:25:15 -07001028 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001029 stashedMatrix.decomposeScale(&scale, &remainder))
1030 {
1031 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001032 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001033 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1034 SkPaint* p = lazyP.set(*paint);
1035 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1036 SkFilterQuality::kLow_SkFilterQuality,
1037 sk_ref_sp(imageFilter)));
1038 imageFilter = p->getImageFilter();
1039 paint = p;
1040 }
reed8c30a812016-04-20 16:36:51 -07001041
junov@chromium.orga907ac32012-02-24 21:54:07 +00001042 // do this before we create the layer. We don't call the public save() since
1043 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001044 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001045
junov@chromium.orga907ac32012-02-24 21:54:07 +00001046 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001047 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001048 if (modifiedRec) {
1049 // In this case there will be no layer in which to stash the matrix so we need to
1050 // revert the prior MCRec to its earlier state.
1051 modifiedRec->fMatrix = stashedMatrix;
1052 }
reed2ff1fce2014-12-11 07:07:37 -08001053 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054 }
1055
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001056 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1057 // the clipRectBounds() call above?
1058 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001059 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001060 }
1061
reed8dc0ccb2015-03-20 06:32:52 -07001062 SkPixelGeometry geo = fProps.pixelGeometry();
1063 if (paint) {
reed76033be2015-03-14 10:54:31 -07001064 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001065 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001066 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001067 }
1068 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069
robertphillips5139e502016-07-19 05:10:40 -07001070 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001071 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001072 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001073 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001074 }
reedb2db8982014-11-13 12:41:02 -08001075
Mike Kleine083f7c2018-02-07 12:54:27 -05001076 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001077
Hal Canary704cd322016-11-07 14:13:52 -05001078 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001079 {
reed70ee31b2015-12-10 13:44:45 -08001080 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001081 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001082 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001083 const bool trackCoverage =
1084 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001085 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001086 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001087 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001088 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001089 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1090 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001091 return;
reed61f501f2015-04-29 08:34:00 -07001092 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001093 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001094 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095
Mike Reedb43a3e02017-02-11 10:18:58 -05001096 // only have a "next" if this new layer doesn't affect the clip (rare)
1097 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 fMCRec->fLayer = layer;
1099 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001100
Mike Reedc61abee2017-02-28 17:45:27 -05001101 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001102 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001103 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001104 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001105
Mike Reedc42a1cd2017-02-14 14:25:14 -05001106 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1107
1108 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1109 if (layer->fNext) {
1110 // need to punch a hole in the previous device, so we don't draw there, given that
1111 // the new top-layer will allow drawing to happen "below" it.
1112 SkRegion hole(ir);
1113 do {
1114 layer = layer->fNext;
1115 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1116 } while (layer->fNext);
1117 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001118}
1119
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001120int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001121 if (0xFF == alpha) {
1122 return this->saveLayer(bounds, nullptr);
1123 } else {
1124 SkPaint tmpPaint;
1125 tmpPaint.setAlpha(alpha);
1126 return this->saveLayer(bounds, &tmpPaint);
1127 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001128}
1129
reed@android.com8a1c16f2008-12-17 15:59:43 +00001130void SkCanvas::internalRestore() {
1131 SkASSERT(fMCStack.count() != 0);
1132
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001133 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134 DeviceCM* layer = fMCRec->fLayer; // may be null
1135 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001136 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137
1138 // now do the normal restore()
1139 fMCRec->~MCRec(); // balanced in save()
1140 fMCStack.pop_back();
1141 fMCRec = (MCRec*)fMCStack.back();
1142
Mike Reedc42a1cd2017-02-14 14:25:14 -05001143 if (fMCRec) {
1144 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1145 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001146
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1148 since if we're being recorded, we don't want to record this (the
1149 recorder will have already recorded the restore).
1150 */
bsalomon49f085d2014-09-05 13:34:00 -07001151 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001152 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001153 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001154 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001155 layer->fPaint.get(),
1156 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001157 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001158 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001159 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001160 delete layer;
reedb679ca82015-04-07 04:40:48 -07001161 } else {
1162 // we're at the root
reeda499f902015-05-01 09:34:31 -07001163 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001164 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001165 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001166 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001167 }
msarettfbfa2582016-08-12 08:29:08 -07001168
1169 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001170 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001171 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1172 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001173}
1174
reede8f30622016-03-23 18:59:25 -07001175sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001176 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001177 props = &fProps;
1178 }
1179 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001180}
1181
reede8f30622016-03-23 18:59:25 -07001182sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001183 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001184 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001185}
1186
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001187SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001188 return this->onImageInfo();
1189}
1190
1191SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001192 SkBaseDevice* dev = this->getDevice();
1193 if (dev) {
1194 return dev->imageInfo();
1195 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001196 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001197 }
1198}
1199
brianosman898235c2016-04-06 07:38:23 -07001200bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001201 return this->onGetProps(props);
1202}
1203
1204bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001205 SkBaseDevice* dev = this->getDevice();
1206 if (dev) {
1207 if (props) {
1208 *props = fProps;
1209 }
1210 return true;
1211 } else {
1212 return false;
1213 }
1214}
1215
reed6ceeebd2016-03-09 14:26:26 -08001216bool SkCanvas::peekPixels(SkPixmap* pmap) {
1217 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001218}
1219
reed884e97c2015-05-26 11:31:54 -07001220bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001221 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001222 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001223}
1224
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001225void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001226 SkPixmap pmap;
1227 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001228 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001229 }
1230 if (info) {
1231 *info = pmap.info();
1232 }
1233 if (rowBytes) {
1234 *rowBytes = pmap.rowBytes();
1235 }
1236 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001237 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001238 }
reed884e97c2015-05-26 11:31:54 -07001239 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001240}
1241
reed884e97c2015-05-26 11:31:54 -07001242bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001243 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001244 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001245}
1246
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001248
Florin Malita53f77bd2017-04-28 13:48:37 -04001249void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1250 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001252 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253 paint = &tmp;
1254 }
reed@google.com4b226022011-01-11 18:32:13 +00001255
reed@google.com8926b162012-03-23 15:36:36 +00001256 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001257
reed@android.com8a1c16f2008-12-17 15:59:43 +00001258 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001259 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001260 paint = &looper.paint();
1261 SkImageFilter* filter = paint->getImageFilter();
1262 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001263 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001264 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1265 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001266 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1267 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001268 }
reed@google.com76dd2772012-01-05 21:15:07 +00001269 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001270 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001271 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272 }
reeda2217ef2016-07-20 06:04:34 -07001273
reed@google.com4e2b3d32011-04-07 14:18:59 +00001274 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275}
1276
reed32704672015-12-16 08:27:10 -08001277/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001278
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001279void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001280 if (dx || dy) {
1281 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001282 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001283
reedfe69b502016-09-12 06:31:48 -07001284 // Translate shouldn't affect the is-scale-translateness of the matrix.
1285 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001286
Mike Reedc42a1cd2017-02-14 14:25:14 -05001287 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001288
reedfe69b502016-09-12 06:31:48 -07001289 this->didTranslate(dx,dy);
1290 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291}
1292
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001293void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001294 SkMatrix m;
1295 m.setScale(sx, sy);
1296 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297}
1298
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001299void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001300 SkMatrix m;
1301 m.setRotate(degrees);
1302 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303}
1304
bungeman7438bfc2016-07-12 15:01:19 -07001305void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1306 SkMatrix m;
1307 m.setRotate(degrees, px, py);
1308 this->concat(m);
1309}
1310
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001311void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001312 SkMatrix m;
1313 m.setSkew(sx, sy);
1314 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001315}
1316
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001317void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001318 if (matrix.isIdentity()) {
1319 return;
1320 }
1321
reed2ff1fce2014-12-11 07:07:37 -08001322 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001323 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001324 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001325
Mike Reed7627fa52017-02-08 10:07:53 -05001326 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001327
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001328 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001329}
1330
reed8c30a812016-04-20 16:36:51 -07001331void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001332 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001333 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001334
Mike Reedc42a1cd2017-02-14 14:25:14 -05001335 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001336}
1337
1338void SkCanvas::setMatrix(const SkMatrix& matrix) {
1339 this->checkForDeferredSave();
1340 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001341 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342}
1343
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001345 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346}
1347
1348//////////////////////////////////////////////////////////////////////////////
1349
Mike Reedc1f77742016-12-09 09:00:50 -05001350void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001351 if (!rect.isFinite()) {
1352 return;
1353 }
reed2ff1fce2014-12-11 07:07:37 -08001354 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001355 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1356 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001357}
1358
Mike Reedc1f77742016-12-09 09:00:50 -05001359void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001360 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001361
Mike Reed7627fa52017-02-08 10:07:53 -05001362 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001363
reedc64eff52015-11-21 12:39:45 -08001364 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001365 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1366 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001367 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001368}
1369
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001370void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1371 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001372 if (fClipRestrictionRect.isEmpty()) {
1373 // we notify the device, but we *dont* resolve deferred saves (since we're just
1374 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001375 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001376 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001377 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001378 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001379 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001380 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001381 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1382 }
1383}
1384
Mike Reedc1f77742016-12-09 09:00:50 -05001385void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001386 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001387 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001388 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001389 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1390 } else {
1391 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001392 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001393}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001394
Mike Reedc1f77742016-12-09 09:00:50 -05001395void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001396 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001397
Brian Salomona3b45d42016-10-03 11:36:16 -04001398 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001399
Mike Reed7627fa52017-02-08 10:07:53 -05001400 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001401
Mike Reed20800c82017-11-15 16:09:04 -05001402 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1403 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001404 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001405}
1406
Mike Reedc1f77742016-12-09 09:00:50 -05001407void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001408 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001409 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001410
1411 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1412 SkRect r;
1413 if (path.isRect(&r)) {
1414 this->onClipRect(r, op, edgeStyle);
1415 return;
1416 }
1417 SkRRect rrect;
1418 if (path.isOval(&r)) {
1419 rrect.setOval(r);
1420 this->onClipRRect(rrect, op, edgeStyle);
1421 return;
1422 }
1423 if (path.isRRect(&rrect)) {
1424 this->onClipRRect(rrect, op, edgeStyle);
1425 return;
1426 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001427 }
robertphillips39f05382015-11-24 09:30:12 -08001428
1429 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001430}
1431
Mike Reedc1f77742016-12-09 09:00:50 -05001432void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001433 AutoValidateClip avc(this);
1434
Brian Salomona3b45d42016-10-03 11:36:16 -04001435 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001436
Mike Reed7627fa52017-02-08 10:07:53 -05001437 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438
Brian Salomona3b45d42016-10-03 11:36:16 -04001439 const SkPath* rasterClipPath = &path;
1440 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001441 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1442 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001443 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001444}
1445
Mike Reedc1f77742016-12-09 09:00:50 -05001446void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001447 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001448 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001449}
1450
Mike Reedc1f77742016-12-09 09:00:50 -05001451void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001452 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001453
reed@google.com5c3d1472011-02-22 19:12:23 +00001454 AutoValidateClip avc(this);
1455
Mike Reed20800c82017-11-15 16:09:04 -05001456 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001457 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001458}
1459
reed@google.com819c9212011-02-23 18:56:55 +00001460#ifdef SK_DEBUG
1461void SkCanvas::validateClip() const {
1462 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001463 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001464 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001465 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001466 return;
1467 }
reed@google.com819c9212011-02-23 18:56:55 +00001468}
1469#endif
1470
Mike Reeda1361362017-03-07 09:37:29 -05001471bool SkCanvas::androidFramework_isClipAA() const {
1472 bool containsAA = false;
1473
1474 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1475
1476 return containsAA;
1477}
1478
1479class RgnAccumulator {
1480 SkRegion* fRgn;
1481public:
1482 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1483 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1484 SkIPoint origin = device->getOrigin();
1485 if (origin.x() | origin.y()) {
1486 rgn->translate(origin.x(), origin.y());
1487 }
1488 fRgn->op(*rgn, SkRegion::kUnion_Op);
1489 }
1490};
1491
1492void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1493 RgnAccumulator accum(rgn);
1494 SkRegion tmp;
1495
1496 rgn->setEmpty();
1497 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001498}
1499
reed@google.com5c3d1472011-02-22 19:12:23 +00001500///////////////////////////////////////////////////////////////////////////////
1501
reed@google.com754de5f2014-02-24 19:38:20 +00001502bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001503 return fMCRec->fRasterClip.isEmpty();
1504
1505 // TODO: should we only use the conservative answer in a recording canvas?
1506#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001507 SkBaseDevice* dev = this->getTopDevice();
1508 // if no device we return true
1509 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001510#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001511}
1512
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001513bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001514 SkBaseDevice* dev = this->getTopDevice();
1515 // if no device we return false
1516 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001517}
1518
msarettfbfa2582016-08-12 08:29:08 -07001519static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1520#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1521 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1522 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1523 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1524 return 0xF != _mm_movemask_ps(mask);
1525#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1526 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1527 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1528 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1529 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1530#else
1531 SkRect devRectAsRect;
1532 SkRect devClipAsRect;
1533 devRect.store(&devRectAsRect.fLeft);
1534 devClip.store(&devClipAsRect.fLeft);
1535 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1536#endif
1537}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001538
msarettfbfa2582016-08-12 08:29:08 -07001539// It's important for this function to not be inlined. Otherwise the compiler will share code
1540// between the fast path and the slow path, resulting in two slow paths.
1541static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1542 const SkMatrix& matrix) {
1543 SkRect deviceRect;
1544 matrix.mapRect(&deviceRect, src);
1545 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1546}
1547
1548bool SkCanvas::quickReject(const SkRect& src) const {
1549#ifdef SK_DEBUG
1550 // Verify that fDeviceClipBounds are set properly.
1551 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001552 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001553 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001554 } else {
msarettfbfa2582016-08-12 08:29:08 -07001555 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001556 }
msarettfbfa2582016-08-12 08:29:08 -07001557
msarett9637ea92016-08-18 14:03:30 -07001558 // Verify that fIsScaleTranslate is set properly.
1559 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001560#endif
1561
msarett9637ea92016-08-18 14:03:30 -07001562 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001563 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1564 }
1565
1566 // We inline the implementation of mapScaleTranslate() for the fast path.
1567 float sx = fMCRec->fMatrix.getScaleX();
1568 float sy = fMCRec->fMatrix.getScaleY();
1569 float tx = fMCRec->fMatrix.getTranslateX();
1570 float ty = fMCRec->fMatrix.getTranslateY();
1571 Sk4f scale(sx, sy, sx, sy);
1572 Sk4f trans(tx, ty, tx, ty);
1573
1574 // Apply matrix.
1575 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1576
1577 // Make sure left < right, top < bottom.
1578 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1579 Sk4f min = Sk4f::Min(ltrb, rblt);
1580 Sk4f max = Sk4f::Max(ltrb, rblt);
1581 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1582 // ARM this sequence generates the fastest (a single instruction).
1583 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1584
1585 // Check if the device rect is NaN or outside the clip.
1586 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001587}
1588
reed@google.com3b3e8952012-08-16 20:53:31 +00001589bool SkCanvas::quickReject(const SkPath& path) const {
1590 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001591}
1592
Mike Klein83c8dd92017-11-28 17:08:45 -05001593SkRect SkCanvas::getLocalClipBounds() const {
1594 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001595 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001596 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001597 }
1598
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001599 SkMatrix inverse;
1600 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001601 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001602 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001603 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001604
Mike Reed42e8c532017-01-23 14:09:13 -05001605 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001606 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001607 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001608
Mike Reedb57b9312018-04-23 12:12:54 -04001609 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001610 inverse.mapRect(&bounds, r);
1611 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001612}
1613
Mike Klein83c8dd92017-11-28 17:08:45 -05001614SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001615 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001616}
1617
reed@android.com8a1c16f2008-12-17 15:59:43 +00001618const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001619 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001620}
1621
Brian Osman11052242016-10-27 14:47:55 -04001622GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001623 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001624 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001625}
1626
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001627GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001628 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001629 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001630}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001631
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001632void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1633 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001634 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001635 if (outer.isEmpty()) {
1636 return;
1637 }
1638 if (inner.isEmpty()) {
1639 this->drawRRect(outer, paint);
1640 return;
1641 }
1642
1643 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001644 // be able to return ...
1645 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001646 //
1647 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001648 if (!outer.getBounds().contains(inner.getBounds())) {
1649 return;
1650 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001651
1652 this->onDrawDRRect(outer, inner, paint);
1653}
1654
reed41af9662015-01-05 07:49:08 -08001655void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001656 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001657 this->onDrawPaint(paint);
1658}
1659
1660void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001661 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001662 // To avoid redundant logic in our culling code and various backends, we always sort rects
1663 // before passing them along.
1664 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001665}
1666
msarettdca352e2016-08-26 06:37:45 -07001667void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001668 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001669 if (region.isEmpty()) {
1670 return;
1671 }
1672
1673 if (region.isRect()) {
1674 return this->drawIRect(region.getBounds(), paint);
1675 }
1676
1677 this->onDrawRegion(region, paint);
1678}
1679
reed41af9662015-01-05 07:49:08 -08001680void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001681 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001682 // To avoid redundant logic in our culling code and various backends, we always sort rects
1683 // before passing them along.
1684 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001685}
1686
1687void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001688 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001689 this->onDrawRRect(rrect, paint);
1690}
1691
1692void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001693 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001694 this->onDrawPoints(mode, count, pts, paint);
1695}
1696
Mike Reede88a1cb2017-03-17 09:50:46 -04001697void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1698 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001699 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001700 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001701 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1702 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Mike Reede88a1cb2017-03-17 09:50:46 -04001703 this->onDrawVerticesObject(vertices.get(), mode, paint);
1704}
1705
1706void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001707 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001708 RETURN_ON_NULL(vertices);
1709 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001710}
1711
1712void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001713 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001714 this->onDrawPath(path, paint);
1715}
1716
reeda85d4d02015-05-06 12:56:48 -07001717void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001718 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001719 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001720 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001721}
1722
Mike Reedc4e31092018-01-30 11:15:27 -05001723// Returns true if the rect can be "filled" : non-empty and finite
1724static bool fillable(const SkRect& r) {
1725 SkScalar w = r.width();
1726 SkScalar h = r.height();
1727 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1728}
1729
reede47829b2015-08-06 10:02:53 -07001730void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1731 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001732 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001733 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001734 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001735 return;
1736 }
1737 this->onDrawImageRect(image, &src, dst, paint, constraint);
1738}
reed41af9662015-01-05 07:49:08 -08001739
reed84984ef2015-07-17 07:09:43 -07001740void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1741 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001742 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001743 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001744}
1745
reede47829b2015-08-06 10:02:53 -07001746void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1747 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001748 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001749 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1750 constraint);
1751}
reede47829b2015-08-06 10:02:53 -07001752
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001753namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001754class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001755public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001756 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1757 if (!origPaint) {
1758 return;
1759 }
1760 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1761 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1762 }
1763 if (origPaint->getMaskFilter()) {
1764 fPaint.writable()->setMaskFilter(nullptr);
1765 }
1766 if (origPaint->isAntiAlias()) {
1767 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001768 }
1769 }
1770
1771 const SkPaint* get() const {
1772 return fPaint;
1773 }
1774
1775private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001776 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001777};
1778} // namespace
1779
reed4c21dc52015-06-25 12:32:03 -07001780void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1781 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001782 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001783 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001784 if (dst.isEmpty()) {
1785 return;
1786 }
msarett552bca92016-08-03 06:53:26 -07001787 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001788 LatticePaint latticePaint(paint);
1789 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001790 } else {
reede47829b2015-08-06 10:02:53 -07001791 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001792 }
reed4c21dc52015-06-25 12:32:03 -07001793}
1794
msarett16882062016-08-16 09:31:08 -07001795void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1796 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001797 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001798 RETURN_ON_NULL(image);
1799 if (dst.isEmpty()) {
1800 return;
1801 }
msarett71df2d72016-09-30 12:41:42 -07001802
1803 SkIRect bounds;
1804 Lattice latticePlusBounds = lattice;
1805 if (!latticePlusBounds.fBounds) {
1806 bounds = SkIRect::MakeWH(image->width(), image->height());
1807 latticePlusBounds.fBounds = &bounds;
1808 }
1809
1810 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001811 LatticePaint latticePaint(paint);
1812 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001813 } else {
1814 this->drawImageRect(image, dst, paint);
1815 }
1816}
1817
reed41af9662015-01-05 07:49:08 -08001818void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001819 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001820 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001821 return;
1822 }
reed41af9662015-01-05 07:49:08 -08001823 this->onDrawBitmap(bitmap, dx, dy, paint);
1824}
1825
reede47829b2015-08-06 10:02:53 -07001826void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001827 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001828 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001829 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001830 return;
1831 }
reede47829b2015-08-06 10:02:53 -07001832 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001833}
1834
reed84984ef2015-07-17 07:09:43 -07001835void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1836 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001837 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001838}
1839
reede47829b2015-08-06 10:02:53 -07001840void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1841 SrcRectConstraint constraint) {
1842 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1843 constraint);
1844}
reede47829b2015-08-06 10:02:53 -07001845
reed41af9662015-01-05 07:49:08 -08001846void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1847 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001848 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001849 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001850 return;
1851 }
msarett552bca92016-08-03 06:53:26 -07001852 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001853 LatticePaint latticePaint(paint);
1854 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001855 } else {
reeda5517e22015-07-14 10:54:12 -07001856 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001857 }
reed41af9662015-01-05 07:49:08 -08001858}
1859
msarettc573a402016-08-02 08:05:56 -07001860void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1861 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001862 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001863 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001864 return;
1865 }
msarett71df2d72016-09-30 12:41:42 -07001866
1867 SkIRect bounds;
1868 Lattice latticePlusBounds = lattice;
1869 if (!latticePlusBounds.fBounds) {
1870 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1871 latticePlusBounds.fBounds = &bounds;
1872 }
1873
1874 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001875 LatticePaint latticePaint(paint);
1876 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001877 } else {
msarett16882062016-08-16 09:31:08 -07001878 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001879 }
msarettc573a402016-08-02 08:05:56 -07001880}
1881
reed71c3c762015-06-24 10:29:17 -07001882void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001883 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001884 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001885 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001886 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001887 if (count <= 0) {
1888 return;
1889 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001890 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001891 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001892 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001893}
1894
reedf70b5312016-03-04 16:36:20 -08001895void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001896 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001897 if (key) {
1898 this->onDrawAnnotation(rect, key, value);
1899 }
1900}
1901
reede47829b2015-08-06 10:02:53 -07001902void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1903 const SkPaint* paint, SrcRectConstraint constraint) {
1904 if (src) {
1905 this->drawImageRect(image, *src, dst, paint, constraint);
1906 } else {
1907 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1908 dst, paint, constraint);
1909 }
1910}
1911void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1912 const SkPaint* paint, SrcRectConstraint constraint) {
1913 if (src) {
1914 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1915 } else {
1916 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1917 dst, paint, constraint);
1918 }
1919}
1920
Mike Reed4204da22017-05-17 08:53:36 -04001921void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001922 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001923 this->onDrawShadowRec(path, rec);
1924}
1925
1926void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1927 SkPaint paint;
1928 const SkRect& pathBounds = path.getBounds();
1929
1930 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1931 while (iter.next()) {
1932 iter.fDevice->drawShadow(path, rec);
1933 }
1934 LOOPER_END
1935}
1936
reed@android.com8a1c16f2008-12-17 15:59:43 +00001937//////////////////////////////////////////////////////////////////////////////
1938// These are the virtual drawing methods
1939//////////////////////////////////////////////////////////////////////////////
1940
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001941void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001942 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001943 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1944 }
1945}
1946
reed41af9662015-01-05 07:49:08 -08001947void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001948 this->internalDrawPaint(paint);
1949}
1950
1951void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001952 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001953
1954 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001955 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001956 }
1957
reed@google.com4e2b3d32011-04-07 14:18:59 +00001958 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001959}
1960
reed41af9662015-01-05 07:49:08 -08001961void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1962 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001963 if ((long)count <= 0) {
1964 return;
1965 }
1966
Mike Reed822128b2017-02-28 16:41:03 -05001967 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001968 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001969 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001970 // special-case 2 points (common for drawing a single line)
1971 if (2 == count) {
1972 r.set(pts[0], pts[1]);
1973 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001974 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001975 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001976 if (!r.isFinite()) {
1977 return;
1978 }
Mike Reed822128b2017-02-28 16:41:03 -05001979 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001980 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1981 return;
1982 }
1983 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001984 }
reed@google.coma584aed2012-05-16 14:06:02 +00001985
halcanary96fcdcc2015-08-27 07:41:13 -07001986 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001987
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001988 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001989
reed@android.com8a1c16f2008-12-17 15:59:43 +00001990 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001991 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001992 }
reed@google.com4b226022011-01-11 18:32:13 +00001993
reed@google.com4e2b3d32011-04-07 14:18:59 +00001994 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001995}
1996
reed4a167172016-08-18 17:15:25 -07001997static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1998 return ((intptr_t)paint.getImageFilter() |
1999#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2000 (intptr_t)canvas->getDrawFilter() |
2001#endif
2002 (intptr_t)paint.getLooper() ) != 0;
2003}
2004
reed41af9662015-01-05 07:49:08 -08002005void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002006 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002007 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002008 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002009 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002010 return;
2011 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002012 }
reed@google.com4b226022011-01-11 18:32:13 +00002013
reed4a167172016-08-18 17:15:25 -07002014 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002015 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002016
reed4a167172016-08-18 17:15:25 -07002017 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002018 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002019 }
2020
2021 LOOPER_END
2022 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002023 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002024 SkDrawIter iter(this);
2025 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002026 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002027 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002028 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002029}
2030
msarett44df6512016-08-25 13:54:30 -07002031void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002032 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002033 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002034 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002035 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2036 return;
2037 }
msarett44df6512016-08-25 13:54:30 -07002038 }
2039
Mike Reed822128b2017-02-28 16:41:03 -05002040 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002041
2042 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002043 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002044 }
2045
2046 LOOPER_END
2047}
2048
reed41af9662015-01-05 07:49:08 -08002049void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002050 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002051 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002052 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002053 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002054 return;
2055 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002056 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002057
Mike Reed822128b2017-02-28 16:41:03 -05002058 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002059
2060 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002061 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002062 }
2063
2064 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002065}
2066
bsalomonac3aa242016-08-19 11:25:19 -07002067void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2068 SkScalar sweepAngle, bool useCenter,
2069 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002070 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002071 if (paint.canComputeFastBounds()) {
2072 SkRect storage;
2073 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002074 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002075 return;
2076 }
bsalomonac3aa242016-08-19 11:25:19 -07002077 }
2078
Mike Reed822128b2017-02-28 16:41:03 -05002079 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002080
2081 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002082 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002083 }
2084
2085 LOOPER_END
2086}
2087
reed41af9662015-01-05 07:49:08 -08002088void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002089 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002090 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002091 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2092 return;
2093 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002094 }
2095
2096 if (rrect.isRect()) {
2097 // call the non-virtual version
2098 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002099 return;
2100 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002101 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002102 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2103 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002104 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002105
Mike Reed822128b2017-02-28 16:41:03 -05002106 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002107
2108 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002109 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002110 }
2111
2112 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002113}
2114
Mike Reed822128b2017-02-28 16:41:03 -05002115void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002116 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002117 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002118 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2119 return;
2120 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002121 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002122
Mike Reed822128b2017-02-28 16:41:03 -05002123 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002124
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002125 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002126 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002127 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002128
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002129 LOOPER_END
2130}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002131
reed41af9662015-01-05 07:49:08 -08002132void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002133 if (!path.isFinite()) {
2134 return;
2135 }
2136
Mike Reed822128b2017-02-28 16:41:03 -05002137 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002138 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002139 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002140 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2141 return;
2142 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002143 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002144
Mike Reed822128b2017-02-28 16:41:03 -05002145 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002146 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002147 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002148 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002149 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002150 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151
Mike Reed822128b2017-02-28 16:41:03 -05002152 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002153
2154 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002155 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002156 }
2157
reed@google.com4e2b3d32011-04-07 14:18:59 +00002158 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002159}
2160
reed262a71b2015-12-05 13:07:27 -08002161bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002162 if (!paint.getImageFilter()) {
2163 return false;
2164 }
2165
2166 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002167 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002168 return false;
2169 }
2170
2171 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2172 // Once we can filter and the filter will return a result larger than itself, we should be
2173 // able to remove this constraint.
2174 // skbug.com/4526
2175 //
2176 SkPoint pt;
2177 ctm.mapXY(x, y, &pt);
2178 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2179 return ir.contains(fMCRec->fRasterClip.getBounds());
2180}
2181
Mike Reedf441cfc2018-04-11 14:50:16 -04002182// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2183// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2184// null.
2185static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2186 if (paintParam) {
2187 *real = *paintParam;
2188 real->setStyle(SkPaint::kFill_Style);
2189 real->setPathEffect(nullptr);
2190 paintParam = real;
2191 }
2192 return paintParam;
2193}
2194
reeda85d4d02015-05-06 12:56:48 -07002195void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002196 SkPaint realPaint;
2197 paint = init_image_paint(&realPaint, paint);
2198
reeda85d4d02015-05-06 12:56:48 -07002199 SkRect bounds = SkRect::MakeXYWH(x, y,
2200 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002201 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002202 SkRect tmp = bounds;
2203 if (paint) {
2204 paint->computeFastBounds(tmp, &tmp);
2205 }
2206 if (this->quickReject(tmp)) {
2207 return;
2208 }
reeda85d4d02015-05-06 12:56:48 -07002209 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002210 // At this point we need a real paint object. If the caller passed null, then we should
2211 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2212 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2213 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002214
reeda2217ef2016-07-20 06:04:34 -07002215 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002216 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2217 *paint);
2218 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002219 special = this->getDevice()->makeSpecial(image);
2220 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002221 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002222 }
2223 }
2224
reed262a71b2015-12-05 13:07:27 -08002225 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2226
reeda85d4d02015-05-06 12:56:48 -07002227 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002228 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002229 if (special) {
2230 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002231 iter.fDevice->ctm().mapXY(x, y, &pt);
2232 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002233 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002234 SkScalarRoundToInt(pt.fY), pnt,
2235 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002236 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002237 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002238 }
reeda85d4d02015-05-06 12:56:48 -07002239 }
halcanary9d524f22016-03-29 09:03:52 -07002240
reeda85d4d02015-05-06 12:56:48 -07002241 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002242}
2243
reed41af9662015-01-05 07:49:08 -08002244void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002245 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002246 SkPaint realPaint;
2247 paint = init_image_paint(&realPaint, paint);
2248
halcanary96fcdcc2015-08-27 07:41:13 -07002249 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002250 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002251 if (paint) {
2252 paint->computeFastBounds(dst, &storage);
2253 }
2254 if (this->quickReject(storage)) {
2255 return;
2256 }
reeda85d4d02015-05-06 12:56:48 -07002257 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002258 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002259
senorblancoc41e7e12015-12-07 12:51:30 -08002260 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002261 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002262
reeda85d4d02015-05-06 12:56:48 -07002263 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002264 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002265 }
halcanary9d524f22016-03-29 09:03:52 -07002266
reeda85d4d02015-05-06 12:56:48 -07002267 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002268}
2269
reed41af9662015-01-05 07:49:08 -08002270void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002271 SkDEBUGCODE(bitmap.validate();)
2272
reed33366972015-10-08 09:22:02 -07002273 if (bitmap.drawsNothing()) {
2274 return;
2275 }
2276
Mike Reedf441cfc2018-04-11 14:50:16 -04002277 SkPaint realPaint;
2278 init_image_paint(&realPaint, paint);
2279 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002280
Mike Reed822128b2017-02-28 16:41:03 -05002281 SkRect bounds;
2282 bitmap.getBounds(&bounds);
2283 bounds.offset(x, y);
2284 bool canFastBounds = paint->canComputeFastBounds();
2285 if (canFastBounds) {
2286 SkRect storage;
2287 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002288 return;
2289 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290 }
reed@google.com4b226022011-01-11 18:32:13 +00002291
reeda2217ef2016-07-20 06:04:34 -07002292 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002293 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2294 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002295 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002296 special = this->getDevice()->makeSpecial(bitmap);
2297 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002298 drawAsSprite = false;
2299 }
2300 }
2301
Mike Reed822128b2017-02-28 16:41:03 -05002302 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002303
2304 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002305 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002306 if (special) {
reed262a71b2015-12-05 13:07:27 -08002307 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002308 iter.fDevice->ctm().mapXY(x, y, &pt);
2309 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002310 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002311 SkScalarRoundToInt(pt.fY), pnt,
2312 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002313 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002314 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002315 }
reed33366972015-10-08 09:22:02 -07002316 }
msarettfbfa2582016-08-12 08:29:08 -07002317
reed33366972015-10-08 09:22:02 -07002318 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002319}
2320
reed@google.com9987ec32011-09-07 11:57:52 +00002321// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002322void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002323 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002324 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002325 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002326 return;
2327 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002328
halcanary96fcdcc2015-08-27 07:41:13 -07002329 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002330 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002331 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2332 return;
2333 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002334 }
reed@google.com3d608122011-11-21 15:16:16 +00002335
reed@google.com33535f32012-09-25 15:37:50 +00002336 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002337 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002338 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002339 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002340
senorblancoc41e7e12015-12-07 12:51:30 -08002341 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002342 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002343
reed@google.com33535f32012-09-25 15:37:50 +00002344 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002345 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002346 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002347
reed@google.com33535f32012-09-25 15:37:50 +00002348 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002349}
2350
reed41af9662015-01-05 07:49:08 -08002351void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002352 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002353 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002354 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002355}
2356
reed4c21dc52015-06-25 12:32:03 -07002357void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2358 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002359 SkPaint realPaint;
2360 paint = init_image_paint(&realPaint, paint);
2361
halcanary96fcdcc2015-08-27 07:41:13 -07002362 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002363 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002364 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2365 return;
2366 }
reed@google.com3d608122011-11-21 15:16:16 +00002367 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002368 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002369
senorblancoc41e7e12015-12-07 12:51:30 -08002370 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002371
reed4c21dc52015-06-25 12:32:03 -07002372 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002373 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002374 }
halcanary9d524f22016-03-29 09:03:52 -07002375
reed4c21dc52015-06-25 12:32:03 -07002376 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002377}
2378
reed41af9662015-01-05 07:49:08 -08002379void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2380 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002381 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002382 SkPaint realPaint;
2383 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002384
halcanary96fcdcc2015-08-27 07:41:13 -07002385 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002386 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002387 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2388 return;
2389 }
reed4c21dc52015-06-25 12:32:03 -07002390 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002391 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002392
senorblancoc41e7e12015-12-07 12:51:30 -08002393 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002394
reed4c21dc52015-06-25 12:32:03 -07002395 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002396 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002397 }
halcanary9d524f22016-03-29 09:03:52 -07002398
reed4c21dc52015-06-25 12:32:03 -07002399 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002400}
2401
msarett16882062016-08-16 09:31:08 -07002402void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2403 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002404 SkPaint realPaint;
2405 paint = init_image_paint(&realPaint, paint);
2406
msarett16882062016-08-16 09:31:08 -07002407 if (nullptr == paint || paint->canComputeFastBounds()) {
2408 SkRect storage;
2409 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2410 return;
2411 }
2412 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002413 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002414
2415 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2416
2417 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002418 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002419 }
2420
2421 LOOPER_END
2422}
2423
2424void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2425 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002426 SkPaint realPaint;
2427 paint = init_image_paint(&realPaint, paint);
2428
msarett16882062016-08-16 09:31:08 -07002429 if (nullptr == paint || paint->canComputeFastBounds()) {
2430 SkRect storage;
2431 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2432 return;
2433 }
2434 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002435 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002436
2437 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2438
2439 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002440 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002441 }
2442
2443 LOOPER_END
2444}
2445
reed@google.come0d9ce82014-04-23 04:00:17 +00002446void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2447 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002448
halcanary96fcdcc2015-08-27 07:41:13 -07002449 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002450
2451 while (iter.next()) {
Herb Derby41f4f312018-06-06 17:45:53 +00002452 auto glyphRun = SkGlyphRun::MakeFromDrawText(
Herb Derby4ffa0272018-06-04 15:49:15 -04002453 looper.paint(), text, byteLength, SkPoint::Make(x, y), fScratchGlyphSet.get());
Herb Derby41f4f312018-06-06 17:45:53 +00002454 iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002455 }
2456
reed@google.com4e2b3d32011-04-07 14:18:59 +00002457 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002458}
2459
reed@google.come0d9ce82014-04-23 04:00:17 +00002460void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2461 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002462
halcanary96fcdcc2015-08-27 07:41:13 -07002463 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002464
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465 while (iter.next()) {
Herb Derby4ffa0272018-06-04 15:49:15 -04002466 auto glyphRun = SkGlyphRun::MakeFromDrawPosText(
2467 looper.paint(), text, byteLength, pos, fScratchGlyphSet.get());
Herb Derby41f4f312018-06-06 17:45:53 +00002468 iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002469 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002470
reed@google.com4e2b3d32011-04-07 14:18:59 +00002471 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002472}
2473
reed@google.come0d9ce82014-04-23 04:00:17 +00002474void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2475 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002476
halcanary96fcdcc2015-08-27 07:41:13 -07002477 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002478
reed@android.com8a1c16f2008-12-17 15:59:43 +00002479 while (iter.next()) {
Herb Derby41f4f312018-06-06 17:45:53 +00002480 auto glyphRun =
Herb Derby4ffa0272018-06-04 15:49:15 -04002481 SkGlyphRun::MakeFromDrawPosTextH(
2482 looper.paint(), text, byteLength, xpos, constY, fScratchGlyphSet.get());
Herb Derby41f4f312018-06-06 17:45:53 +00002483 iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002485
reed@google.com4e2b3d32011-04-07 14:18:59 +00002486 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002487}
2488
reed@google.come0d9ce82014-04-23 04:00:17 +00002489void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2490 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002491 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002492
reed@android.com8a1c16f2008-12-17 15:59:43 +00002493 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002494 iter.fDevice->drawTextOnPath(text, byteLength, path, matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002495 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002496
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002497 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002498}
2499
reed45561a02016-07-07 12:47:17 -07002500void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2501 const SkRect* cullRect, const SkPaint& paint) {
2502 if (cullRect && this->quickReject(*cullRect)) {
2503 return;
2504 }
2505
2506 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2507
2508 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002509 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002510 }
2511
2512 LOOPER_END
2513}
2514
fmalita00d5c2c2014-08-21 08:53:26 -07002515void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2516 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002517 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002518 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002519 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002520 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002521 SkRect tmp;
2522 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2523 return;
2524 }
2525 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002526 }
2527
fmalita024f9962015-03-03 19:08:17 -08002528 // We cannot filter in the looper as we normally do, because the paint is
2529 // incomplete at this point (text-related attributes are embedded within blob run paints).
2530 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002531 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002532
fmalita85d5eb92015-03-04 11:20:12 -08002533 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002534
fmalitaaa1b9122014-08-28 14:32:24 -07002535 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002536 iter.fDevice->drawTextBlob(blob, x, y, looper.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002537 }
2538
fmalitaaa1b9122014-08-28 14:32:24 -07002539 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002540
2541 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002542}
2543
Cary Clark2a475ea2017-04-28 15:35:12 -04002544void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2545 this->drawText(string.c_str(), string.size(), x, y, paint);
2546}
2547
reed@google.come0d9ce82014-04-23 04:00:17 +00002548// These will become non-virtual, so they always call the (virtual) onDraw... method
2549void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2550 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002551 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002552 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002553 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002554 this->onDrawText(text, byteLength, x, y, paint);
2555 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002556}
2557void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2558 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002559 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002560 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002561 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002562 this->onDrawPosText(text, byteLength, pos, paint);
2563 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002564}
2565void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2566 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002567 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002568 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002569 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002570 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2571 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002572}
2573void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2574 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002575 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002576 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002577 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002578 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2579 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002580}
reed45561a02016-07-07 12:47:17 -07002581void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2582 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002583 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002584 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002585 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002586 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2587 }
2588}
fmalita00d5c2c2014-08-21 08:53:26 -07002589void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2590 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002591 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002592 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002593 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002594 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002595}
reed@google.come0d9ce82014-04-23 04:00:17 +00002596
Mike Reede88a1cb2017-03-17 09:50:46 -04002597void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2598 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002599 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2600
2601 while (iter.next()) {
2602 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002603 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002604 }
2605
2606 LOOPER_END
2607}
2608
dandovb3c9d1c2014-08-12 08:34:29 -07002609void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002610 const SkPoint texCoords[4], SkBlendMode bmode,
2611 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002612 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002613 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002614 return;
2615 }
mtklein6cfa73a2014-08-13 13:33:49 -07002616
Mike Reedfaba3712016-11-03 14:45:31 -04002617 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002618}
2619
2620void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002621 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002622 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002623 // Since a patch is always within the convex hull of the control points, we discard it when its
2624 // bounding rectangle is completely outside the current clip.
2625 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002626 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002627 if (this->quickReject(bounds)) {
2628 return;
2629 }
mtklein6cfa73a2014-08-13 13:33:49 -07002630
Mike Reed435071e2017-05-23 11:22:56 -04002631 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2632
halcanary96fcdcc2015-08-27 07:41:13 -07002633 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002634
dandovecfff212014-08-04 10:02:00 -07002635 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002636 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002637 }
mtklein6cfa73a2014-08-13 13:33:49 -07002638
dandovecfff212014-08-04 10:02:00 -07002639 LOOPER_END
2640}
2641
reeda8db7282015-07-07 10:22:31 -07002642void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002643#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002644 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002645#endif
reede3b38ce2016-01-08 09:18:44 -08002646 RETURN_ON_NULL(dr);
2647 if (x || y) {
2648 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2649 this->onDrawDrawable(dr, &matrix);
2650 } else {
2651 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002652 }
2653}
2654
reeda8db7282015-07-07 10:22:31 -07002655void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002656#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002657 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002658#endif
reede3b38ce2016-01-08 09:18:44 -08002659 RETURN_ON_NULL(dr);
2660 if (matrix && matrix->isIdentity()) {
2661 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002662 }
reede3b38ce2016-01-08 09:18:44 -08002663 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002664}
2665
2666void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002667 // drawable bounds are no longer reliable (e.g. android displaylist)
2668 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002669 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002670}
2671
reed71c3c762015-06-24 10:29:17 -07002672void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002673 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002674 const SkRect* cull, const SkPaint* paint) {
2675 if (cull && this->quickReject(*cull)) {
2676 return;
2677 }
2678
2679 SkPaint pnt;
2680 if (paint) {
2681 pnt = *paint;
2682 }
halcanary9d524f22016-03-29 09:03:52 -07002683
halcanary96fcdcc2015-08-27 07:41:13 -07002684 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002685 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002686 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002687 }
2688 LOOPER_END
2689}
2690
reedf70b5312016-03-04 16:36:20 -08002691void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2692 SkASSERT(key);
2693
2694 SkPaint paint;
2695 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2696 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002697 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002698 }
2699 LOOPER_END
2700}
2701
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702//////////////////////////////////////////////////////////////////////////////
2703// These methods are NOT virtual, and therefore must call back into virtual
2704// methods, rather than actually drawing themselves.
2705//////////////////////////////////////////////////////////////////////////////
2706
reed374772b2016-10-05 17:33:02 -07002707void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002709 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002710 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711 this->drawPaint(paint);
2712}
2713
2714void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002715 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2717}
2718
Mike Reed3661bc92017-02-22 13:21:42 -05002719void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002720 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721 pts[0].set(x0, y0);
2722 pts[1].set(x1, y1);
2723 this->drawPoints(kLines_PointMode, 2, pts, paint);
2724}
2725
Mike Reed3661bc92017-02-22 13:21:42 -05002726void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 if (radius < 0) {
2728 radius = 0;
2729 }
2730
2731 SkRect r;
2732 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002733 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002734}
2735
2736void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2737 const SkPaint& paint) {
2738 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002739 SkRRect rrect;
2740 rrect.setRectXY(r, rx, ry);
2741 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742 } else {
2743 this->drawRect(r, paint);
2744 }
2745}
2746
reed@android.com8a1c16f2008-12-17 15:59:43 +00002747void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2748 SkScalar sweepAngle, bool useCenter,
2749 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002750 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002751 if (oval.isEmpty() || !sweepAngle) {
2752 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753 }
bsalomon21af9ca2016-08-25 12:29:23 -07002754 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002755}
2756
2757void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2758 const SkPath& path, SkScalar hOffset,
2759 SkScalar vOffset, const SkPaint& paint) {
2760 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002761
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762 matrix.setTranslate(hOffset, vOffset);
2763 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2764}
2765
reed@android.comf76bacf2009-05-13 14:00:33 +00002766///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002767
Mike Klein88d90712018-01-27 17:30:04 +00002768/**
2769 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2770 * against the playback cost of recursing into the subpicture to get at its actual ops.
2771 *
2772 * For now we pick a conservatively small value, though measurement (and other heuristics like
2773 * the type of ops contained) may justify changing this value.
2774 */
2775#define kMaxPictureOpsToUnrollInsteadOfRef 1
2776
reedd5fa1a42014-08-09 11:08:05 -07002777void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002778 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002779 RETURN_ON_NULL(picture);
2780
reede3b38ce2016-01-08 09:18:44 -08002781 if (matrix && matrix->isIdentity()) {
2782 matrix = nullptr;
2783 }
Mike Klein88d90712018-01-27 17:30:04 +00002784 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2785 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2786 picture->playback(this);
2787 } else {
2788 this->onDrawPicture(picture, matrix, paint);
2789 }
reedd5fa1a42014-08-09 11:08:05 -07002790}
robertphillips9b14f262014-06-04 05:40:44 -07002791
reedd5fa1a42014-08-09 11:08:05 -07002792void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2793 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002794 if (!paint || paint->canComputeFastBounds()) {
2795 SkRect bounds = picture->cullRect();
2796 if (paint) {
2797 paint->computeFastBounds(bounds, &bounds);
2798 }
2799 if (matrix) {
2800 matrix->mapRect(&bounds);
2801 }
2802 if (this->quickReject(bounds)) {
2803 return;
2804 }
2805 }
2806
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002807 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002808 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809}
2810
reed@android.com8a1c16f2008-12-17 15:59:43 +00002811///////////////////////////////////////////////////////////////////////////////
2812///////////////////////////////////////////////////////////////////////////////
2813
reed3aafe112016-08-18 12:45:34 -07002814SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002815 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816
2817 SkASSERT(canvas);
2818
reed3aafe112016-08-18 12:45:34 -07002819 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002820 fDone = !fImpl->next();
2821}
2822
2823SkCanvas::LayerIter::~LayerIter() {
2824 fImpl->~SkDrawIter();
2825}
2826
2827void SkCanvas::LayerIter::next() {
2828 fDone = !fImpl->next();
2829}
2830
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002831SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002832 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833}
2834
2835const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002836 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837}
2838
2839const SkPaint& SkCanvas::LayerIter::paint() const {
2840 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002841 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842 paint = &fDefaultPaint;
2843 }
2844 return *paint;
2845}
2846
Mike Reedca37f322018-03-08 13:22:16 -05002847SkIRect SkCanvas::LayerIter::clipBounds() const {
2848 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002849}
2850
reed@android.com8a1c16f2008-12-17 15:59:43 +00002851int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2852int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002853
2854///////////////////////////////////////////////////////////////////////////////
2855
Brian Osman10fc6fd2018-03-02 11:01:10 -05002856// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002857static bool supported_for_raster_canvas(const SkImageInfo& info) {
2858 switch (info.alphaType()) {
2859 case kPremul_SkAlphaType:
2860 case kOpaque_SkAlphaType:
2861 break;
2862 default:
2863 return false;
2864 }
2865
2866 switch (info.colorType()) {
2867 case kAlpha_8_SkColorType:
2868 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002869 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002870 case kRGBA_F16_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002871 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002872 break;
2873 default:
2874 return false;
2875 }
2876
2877 return true;
2878}
2879
Mike Reed5df49342016-11-12 08:06:55 -06002880std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002881 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002882 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002883 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002884 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002885
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002886 SkBitmap bitmap;
2887 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002888 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002889 }
Mike Reed12f77342017-11-08 11:19:52 -05002890
2891 return props ?
2892 skstd::make_unique<SkCanvas>(bitmap, *props) :
2893 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002894}
reedd5fa1a42014-08-09 11:08:05 -07002895
2896///////////////////////////////////////////////////////////////////////////////
2897
Florin Malitaee424ac2016-12-01 12:47:59 -05002898SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2899 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2900
Florin Malita439ace92016-12-02 12:05:41 -05002901SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2902 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2903
Herb Derbyefe39bc2018-05-01 17:06:20 -04002904SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002905 : INHERITED(device) {}
2906
Florin Malitaee424ac2016-12-01 12:47:59 -05002907SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2908 (void)this->INHERITED::getSaveLayerStrategy(rec);
2909 return kNoLayer_SaveLayerStrategy;
2910}
2911
2912///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002913
reed73603f32016-09-20 08:42:38 -07002914static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2915static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2916static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2917static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2918static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2919static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002920
2921///////////////////////////////////////////////////////////////////////////////////////////////////
2922
2923SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2924 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002925 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002926 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2927 SkIPoint origin = dev->getOrigin();
2928 SkMatrix ctm = this->getTotalMatrix();
2929 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2930
2931 SkIRect clip = fMCRec->fRasterClip.getBounds();
2932 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002933 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002934 clip.setEmpty();
2935 }
2936
2937 fAllocator->updateHandle(handle, ctm, clip);
2938 return handle;
2939 }
2940 return nullptr;
2941}
2942
2943static bool install(SkBitmap* bm, const SkImageInfo& info,
2944 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002945 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002946}
2947
2948SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2949 SkBitmap* bm) {
2950 SkRasterHandleAllocator::Rec rec;
2951 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2952 return nullptr;
2953 }
2954 return rec.fHandle;
2955}
2956
2957std::unique_ptr<SkCanvas>
2958SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2959 const SkImageInfo& info, const Rec* rec) {
2960 if (!alloc || !supported_for_raster_canvas(info)) {
2961 return nullptr;
2962 }
2963
2964 SkBitmap bm;
2965 Handle hndl;
2966
2967 if (rec) {
2968 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2969 } else {
2970 hndl = alloc->allocBitmap(info, &bm);
2971 }
2972 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2973}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002974
2975///////////////////////////////////////////////////////////////////////////////////////////////////
2976
2977