blob: dcff1b0cc3dfb512aa6bd2b8dd1e49cf31cc39a8 [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 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593}
594
reed@google.comcde92112011-07-06 20:00:52 +0000595SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000596 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700597 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000598{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000599 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000600
halcanary96fcdcc2015-08-27 07:41:13 -0700601 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000602}
603
reed96a857e2015-01-25 10:33:58 -0800604SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000605 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800606 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000607{
608 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400609 this->init(sk_make_sp<SkNoPixelsDevice>(
610 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps), kDefault_InitFlags);
reedd9544982014-09-09 18:46:22 -0700611}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000612
reed78e27682014-11-19 08:04:34 -0800613SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700614 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700615 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700616{
617 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700618
Mike Reed566e53c2017-03-10 10:49:45 -0500619 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400620 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps), flags);
reedd9544982014-09-09 18:46:22 -0700621}
622
Herb Derbyefe39bc2018-05-01 17:06:20 -0400623SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000624 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700625 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000626{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000627 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700628
reedd9544982014-09-09 18:46:22 -0700629 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000630}
631
Herb Derbyefe39bc2018-05-01 17:06:20 -0400632SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device, InitFlags flags)
robertphillipsfcf78292015-06-19 11:49:52 -0700633 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700634 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700635{
636 inc_canvas();
637
638 this->init(device, flags);
639}
640
reed4a8126e2014-09-22 07:29:03 -0700641SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700642 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700643 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700644{
645 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700646
Mike Reed910ca0f2018-04-25 13:04:05 -0400647 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400648 this->init(device, kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700649}
reed29c857d2014-09-21 10:25:07 -0700650
Mike Reed356f7c22017-01-10 11:58:39 -0500651SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
652 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700653 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
654 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500655 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700656{
657 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700658
Mike Reed910ca0f2018-04-25 13:04:05 -0400659 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400660 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661}
662
Mike Reed356f7c22017-01-10 11:58:39 -0500663SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
664
Matt Sarett31f99ce2017-04-11 08:46:01 -0400665#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
666SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
667 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
668 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
669 , fAllocator(nullptr)
670{
671 inc_canvas();
672
673 SkBitmap tmp(bitmap);
674 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400675 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400676 this->init(device, kDefault_InitFlags);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400677}
678#endif
679
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680SkCanvas::~SkCanvas() {
681 // free up the contents of our deque
682 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000683
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684 this->internalRestore(); // restore the last, since we're going away
685
halcanary385fe4d2015-08-26 13:07:48 -0700686 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000687
reed@android.com8a1c16f2008-12-17 15:59:43 +0000688 dec_canvas();
689}
690
fmalita53d9f1c2016-01-25 06:23:54 -0800691#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692SkDrawFilter* SkCanvas::getDrawFilter() const {
693 return fMCRec->fFilter;
694}
695
696SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700697 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000698 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
699 return filter;
700}
fmalita77650002016-01-21 18:47:11 -0800701#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000702
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000703SkMetaData& SkCanvas::getMetaData() {
704 // metadata users are rare, so we lazily allocate it. If that changes we
705 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700706 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000707 fMetaData = new SkMetaData;
708 }
709 return *fMetaData;
710}
711
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712///////////////////////////////////////////////////////////////////////////////
713
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000714void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700715 this->onFlush();
716}
717
718void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000719 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000720 if (device) {
721 device->flush();
722 }
723}
724
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000725SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000726 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000727 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
728}
729
senorblancoafc7cce2016-02-02 18:44:15 -0800730SkIRect SkCanvas::getTopLayerBounds() const {
731 SkBaseDevice* d = this->getTopDevice();
732 if (!d) {
733 return SkIRect::MakeEmpty();
734 }
735 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
736}
737
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000738SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000739 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000740 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000741 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400742 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000743}
744
Florin Malita0ed3b642017-01-13 16:56:38 +0000745SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400746 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000747}
748
Mike Reed353196f2017-07-21 11:01:18 -0400749bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000750 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400751 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000752}
753
Mike Reed353196f2017-07-21 11:01:18 -0400754bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
755 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400756}
757
758bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
759 SkPixmap pm;
760 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
761}
762
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000763bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400764 SkPixmap pm;
765 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700766 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000767 }
768 return false;
769}
770
Matt Sarett03dd6d52017-01-23 12:15:09 -0500771bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000772 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000773 SkBaseDevice* device = this->getDevice();
774 if (!device) {
775 return false;
776 }
777
Matt Sarett03dd6d52017-01-23 12:15:09 -0500778 // This check gives us an early out and prevents generation ID churn on the surface.
779 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
780 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
781 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
782 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000783 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000784
Matt Sarett03dd6d52017-01-23 12:15:09 -0500785 // Tell our owning surface to bump its generation ID.
786 const bool completeOverwrite =
787 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700788 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700789
Matt Sarett03dd6d52017-01-23 12:15:09 -0500790 // This can still fail, most notably in the case of a invalid color type or alpha type
791 // conversion. We could pull those checks into this function and avoid the unnecessary
792 // generation ID bump. But then we would be performing those checks twice, since they
793 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400794 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000795}
reed@google.com51df9e32010-12-23 19:29:18 +0000796
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797//////////////////////////////////////////////////////////////////////////////
798
reed2ff1fce2014-12-11 07:07:37 -0800799void SkCanvas::checkForDeferredSave() {
800 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800801 this->doSave();
802 }
803}
804
reedf0090cb2014-11-26 08:55:51 -0800805int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800806#ifdef SK_DEBUG
807 int count = 0;
808 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
809 for (;;) {
810 const MCRec* rec = (const MCRec*)iter.next();
811 if (!rec) {
812 break;
813 }
814 count += 1 + rec->fDeferredSaveCount;
815 }
816 SkASSERT(count == fSaveCount);
817#endif
818 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800819}
820
821int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800822 fSaveCount += 1;
823 fMCRec->fDeferredSaveCount += 1;
824 return this->getSaveCount() - 1; // return our prev value
825}
826
827void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800828 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700829
830 SkASSERT(fMCRec->fDeferredSaveCount > 0);
831 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800832 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800833}
834
835void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800836 if (fMCRec->fDeferredSaveCount > 0) {
837 SkASSERT(fSaveCount > 1);
838 fSaveCount -= 1;
839 fMCRec->fDeferredSaveCount -= 1;
840 } else {
841 // check for underflow
842 if (fMCStack.count() > 1) {
843 this->willRestore();
844 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700845 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800846 this->internalRestore();
847 this->didRestore();
848 }
reedf0090cb2014-11-26 08:55:51 -0800849 }
850}
851
852void SkCanvas::restoreToCount(int count) {
853 // sanity check
854 if (count < 1) {
855 count = 1;
856 }
mtkleinf0f14112014-12-12 08:46:25 -0800857
reedf0090cb2014-11-26 08:55:51 -0800858 int n = this->getSaveCount() - count;
859 for (int i = 0; i < n; ++i) {
860 this->restore();
861 }
862}
863
reed2ff1fce2014-12-11 07:07:37 -0800864void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000865 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700866 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000868
Mike Reedc42a1cd2017-02-14 14:25:14 -0500869 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870}
871
reed4960eee2015-12-18 07:09:18 -0800872bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400873 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874}
875
reed4960eee2015-12-18 07:09:18 -0800876bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700877 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500878 SkIRect clipBounds = this->getDeviceClipBounds();
879 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000880 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000881 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000882
reed96e657d2015-03-10 17:30:07 -0700883 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
884
Robert Phillips12078432018-05-17 11:17:39 -0400885 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
886 // If the image filter DAG affects transparent black then we will need to render
887 // out to the clip bounds
888 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000889 }
Robert Phillips12078432018-05-17 11:17:39 -0400890
891 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700892 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000893 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700894 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400895 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400897 inputSaveLayerBounds = clipBounds;
898 }
899
900 if (imageFilter) {
901 // expand the clip bounds by the image filter DAG to include extra content that might
902 // be required by the image filters.
903 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
904 SkImageFilter::kReverse_MapDirection,
905 &inputSaveLayerBounds);
906 }
907
908 SkIRect clippedSaveLayerBounds;
909 if (bounds) {
910 // For better or for worse, user bounds currently act as a hard clip on the layer's
911 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
912 clippedSaveLayerBounds = inputSaveLayerBounds;
913 } else {
914 // If there are no user bounds, we don't want to artificially restrict the resulting
915 // layer bounds, so allow the expanded clip bounds free reign.
916 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000917 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800918
919 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400920 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800921 if (BoundsAffectsClip(saveLayerFlags)) {
922 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
923 fMCRec->fRasterClip.setEmpty();
924 fDeviceClipBounds.setEmpty();
925 }
926 return false;
927 }
Robert Phillips12078432018-05-17 11:17:39 -0400928 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929
reed4960eee2015-12-18 07:09:18 -0800930 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700931 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400932 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
933 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000934 }
935
936 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400937 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000938 }
Robert Phillips12078432018-05-17 11:17:39 -0400939
junov@chromium.orga907ac32012-02-24 21:54:07 +0000940 return true;
941}
942
reed4960eee2015-12-18 07:09:18 -0800943int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
944 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000945}
946
reed70ee31b2015-12-10 13:44:45 -0800947int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800948 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
949}
950
Cary Clarke041e312018-03-06 13:00:52 -0500951int SkCanvas::saveLayer(const SaveLayerRec& rec) {
952 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
reed4960eee2015-12-18 07:09:18 -0800953 fSaveCount += 1;
Cary Clarke041e312018-03-06 13:00:52 -0500954 this->internalSaveLayer(rec, strategy);
reed4960eee2015-12-18 07:09:18 -0800955 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800956}
957
reeda2217ef2016-07-20 06:04:34 -0700958void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500959 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500960 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700961 SkDraw draw;
962 SkRasterClip rc;
963 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
964 if (!dst->accessPixels(&draw.fDst)) {
965 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800966 }
reeda2217ef2016-07-20 06:04:34 -0700967 draw.fMatrix = &SkMatrix::I();
968 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800969
970 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500971 if (filter) {
972 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
973 }
reeda2217ef2016-07-20 06:04:34 -0700974
Mike Reedc42a1cd2017-02-14 14:25:14 -0500975 int x = src->getOrigin().x() - dstOrigin.x();
976 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700977 auto special = src->snapSpecial();
978 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400979 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700980 }
robertphillips7354a4b2015-12-16 05:08:27 -0800981}
reed70ee31b2015-12-10 13:44:45 -0800982
Mike Kleine083f7c2018-02-07 12:54:27 -0500983static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500984 // Need to force L32 for now if we have an image filter.
985 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
986 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500987 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800988 }
Mike Klein649fb732018-02-26 15:09:16 -0500989
990 SkColorType ct = prev.colorType();
991 if (prev.bytesPerPixel() <= 4) {
992 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
993 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
994 ct = kN32_SkColorType;
995 }
996 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800997}
998
reed4960eee2015-12-18 07:09:18 -0800999void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1000 const SkRect* bounds = rec.fBounds;
1001 const SkPaint* paint = rec.fPaint;
1002 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1003
reed8c30a812016-04-20 16:36:51 -07001004 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001005 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001006 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -04001007 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -07001008 SkMatrix remainder;
1009 SkSize scale;
1010 /*
1011 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1012 * but they do handle scaling. To accommodate this, we do the following:
1013 *
1014 * 1. Stash off the current CTM
1015 * 2. Decompose the CTM into SCALE and REMAINDER
1016 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1017 * contains the REMAINDER
1018 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1019 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1020 * of the original imagefilter, and draw that (via drawSprite)
1021 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1022 *
1023 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1024 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1025 */
reed96a04f32016-04-25 09:25:15 -07001026 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001027 stashedMatrix.decomposeScale(&scale, &remainder))
1028 {
1029 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001030 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001031 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1032 SkPaint* p = lazyP.set(*paint);
1033 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1034 SkFilterQuality::kLow_SkFilterQuality,
1035 sk_ref_sp(imageFilter)));
1036 imageFilter = p->getImageFilter();
1037 paint = p;
1038 }
reed8c30a812016-04-20 16:36:51 -07001039
junov@chromium.orga907ac32012-02-24 21:54:07 +00001040 // do this before we create the layer. We don't call the public save() since
1041 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001042 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001043
junov@chromium.orga907ac32012-02-24 21:54:07 +00001044 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001045 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001046 if (modifiedRec) {
1047 // In this case there will be no layer in which to stash the matrix so we need to
1048 // revert the prior MCRec to its earlier state.
1049 modifiedRec->fMatrix = stashedMatrix;
1050 }
reed2ff1fce2014-12-11 07:07:37 -08001051 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001052 }
1053
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001054 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1055 // the clipRectBounds() call above?
1056 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001057 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001058 }
1059
reed8dc0ccb2015-03-20 06:32:52 -07001060 SkPixelGeometry geo = fProps.pixelGeometry();
1061 if (paint) {
reed76033be2015-03-14 10:54:31 -07001062 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001063 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001064 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001065 }
1066 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067
robertphillips5139e502016-07-19 05:10:40 -07001068 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001069 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001070 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001071 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001072 }
reedb2db8982014-11-13 12:41:02 -08001073
Mike Kleine083f7c2018-02-07 12:54:27 -05001074 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001075
Hal Canary704cd322016-11-07 14:13:52 -05001076 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001077 {
reed70ee31b2015-12-10 13:44:45 -08001078 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001079 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001080 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001081 const bool trackCoverage =
1082 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001083 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001084 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001085 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001086 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001087 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1088 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001089 return;
reed61f501f2015-04-29 08:34:00 -07001090 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001091 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001092 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093
Mike Reedb43a3e02017-02-11 10:18:58 -05001094 // only have a "next" if this new layer doesn't affect the clip (rare)
1095 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001096 fMCRec->fLayer = layer;
1097 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001098
Mike Reedc61abee2017-02-28 17:45:27 -05001099 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001100 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001101 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001102 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001103
Mike Reedc42a1cd2017-02-14 14:25:14 -05001104 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1105
1106 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1107 if (layer->fNext) {
1108 // need to punch a hole in the previous device, so we don't draw there, given that
1109 // the new top-layer will allow drawing to happen "below" it.
1110 SkRegion hole(ir);
1111 do {
1112 layer = layer->fNext;
1113 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1114 } while (layer->fNext);
1115 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001116}
1117
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001118int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001119 if (0xFF == alpha) {
1120 return this->saveLayer(bounds, nullptr);
1121 } else {
1122 SkPaint tmpPaint;
1123 tmpPaint.setAlpha(alpha);
1124 return this->saveLayer(bounds, &tmpPaint);
1125 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001126}
1127
reed@android.com8a1c16f2008-12-17 15:59:43 +00001128void SkCanvas::internalRestore() {
1129 SkASSERT(fMCStack.count() != 0);
1130
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001131 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001132 DeviceCM* layer = fMCRec->fLayer; // may be null
1133 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001134 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001135
1136 // now do the normal restore()
1137 fMCRec->~MCRec(); // balanced in save()
1138 fMCStack.pop_back();
1139 fMCRec = (MCRec*)fMCStack.back();
1140
Mike Reedc42a1cd2017-02-14 14:25:14 -05001141 if (fMCRec) {
1142 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1143 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001144
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1146 since if we're being recorded, we don't want to record this (the
1147 recorder will have already recorded the restore).
1148 */
bsalomon49f085d2014-09-05 13:34:00 -07001149 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001150 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001151 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001152 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001153 layer->fPaint.get(),
1154 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001155 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001156 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001157 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001158 delete layer;
reedb679ca82015-04-07 04:40:48 -07001159 } else {
1160 // we're at the root
reeda499f902015-05-01 09:34:31 -07001161 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001162 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001163 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001164 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001165 }
msarettfbfa2582016-08-12 08:29:08 -07001166
1167 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001168 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001169 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1170 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001171}
1172
reede8f30622016-03-23 18:59:25 -07001173sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001174 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001175 props = &fProps;
1176 }
1177 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001178}
1179
reede8f30622016-03-23 18:59:25 -07001180sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001181 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001182 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001183}
1184
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001185SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001186 return this->onImageInfo();
1187}
1188
1189SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001190 SkBaseDevice* dev = this->getDevice();
1191 if (dev) {
1192 return dev->imageInfo();
1193 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001194 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001195 }
1196}
1197
brianosman898235c2016-04-06 07:38:23 -07001198bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001199 return this->onGetProps(props);
1200}
1201
1202bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001203 SkBaseDevice* dev = this->getDevice();
1204 if (dev) {
1205 if (props) {
1206 *props = fProps;
1207 }
1208 return true;
1209 } else {
1210 return false;
1211 }
1212}
1213
reed6ceeebd2016-03-09 14:26:26 -08001214bool SkCanvas::peekPixels(SkPixmap* pmap) {
1215 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001216}
1217
reed884e97c2015-05-26 11:31:54 -07001218bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001219 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001220 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001221}
1222
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001223void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001224 SkPixmap pmap;
1225 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001226 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001227 }
1228 if (info) {
1229 *info = pmap.info();
1230 }
1231 if (rowBytes) {
1232 *rowBytes = pmap.rowBytes();
1233 }
1234 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001235 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001236 }
reed884e97c2015-05-26 11:31:54 -07001237 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001238}
1239
reed884e97c2015-05-26 11:31:54 -07001240bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001241 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001242 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001243}
1244
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246
Florin Malita53f77bd2017-04-28 13:48:37 -04001247void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1248 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001250 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 paint = &tmp;
1252 }
reed@google.com4b226022011-01-11 18:32:13 +00001253
reed@google.com8926b162012-03-23 15:36:36 +00001254 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001255
reed@android.com8a1c16f2008-12-17 15:59:43 +00001256 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001257 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001258 paint = &looper.paint();
1259 SkImageFilter* filter = paint->getImageFilter();
1260 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001261 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001262 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1263 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001264 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1265 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001266 }
reed@google.com76dd2772012-01-05 21:15:07 +00001267 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001268 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001269 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270 }
reeda2217ef2016-07-20 06:04:34 -07001271
reed@google.com4e2b3d32011-04-07 14:18:59 +00001272 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273}
1274
reed32704672015-12-16 08:27:10 -08001275/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001276
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001277void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001278 if (dx || dy) {
1279 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001280 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001281
reedfe69b502016-09-12 06:31:48 -07001282 // Translate shouldn't affect the is-scale-translateness of the matrix.
1283 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001284
Mike Reedc42a1cd2017-02-14 14:25:14 -05001285 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001286
reedfe69b502016-09-12 06:31:48 -07001287 this->didTranslate(dx,dy);
1288 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289}
1290
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001291void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001292 SkMatrix m;
1293 m.setScale(sx, sy);
1294 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295}
1296
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001297void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001298 SkMatrix m;
1299 m.setRotate(degrees);
1300 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301}
1302
bungeman7438bfc2016-07-12 15:01:19 -07001303void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1304 SkMatrix m;
1305 m.setRotate(degrees, px, py);
1306 this->concat(m);
1307}
1308
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001309void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001310 SkMatrix m;
1311 m.setSkew(sx, sy);
1312 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001313}
1314
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001315void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001316 if (matrix.isIdentity()) {
1317 return;
1318 }
1319
reed2ff1fce2014-12-11 07:07:37 -08001320 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001321 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001322 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001323
Mike Reed7627fa52017-02-08 10:07:53 -05001324 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001325
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001326 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001327}
1328
reed8c30a812016-04-20 16:36:51 -07001329void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001330 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001331 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001332
Mike Reedc42a1cd2017-02-14 14:25:14 -05001333 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001334}
1335
1336void SkCanvas::setMatrix(const SkMatrix& matrix) {
1337 this->checkForDeferredSave();
1338 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001339 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340}
1341
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001343 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344}
1345
1346//////////////////////////////////////////////////////////////////////////////
1347
Mike Reedc1f77742016-12-09 09:00:50 -05001348void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001349 if (!rect.isFinite()) {
1350 return;
1351 }
reed2ff1fce2014-12-11 07:07:37 -08001352 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001353 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1354 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001355}
1356
Mike Reedc1f77742016-12-09 09:00:50 -05001357void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001358 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001359
Mike Reed7627fa52017-02-08 10:07:53 -05001360 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001361
reedc64eff52015-11-21 12:39:45 -08001362 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001363 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1364 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001365 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366}
1367
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001368void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1369 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001370 if (fClipRestrictionRect.isEmpty()) {
1371 // we notify the device, but we *dont* resolve deferred saves (since we're just
1372 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001373 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001374 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001375 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001376 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001377 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001378 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001379 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1380 }
1381}
1382
Mike Reedc1f77742016-12-09 09:00:50 -05001383void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001384 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001385 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001386 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001387 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1388 } else {
1389 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001390 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001391}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001392
Mike Reedc1f77742016-12-09 09:00:50 -05001393void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001394 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001395
Brian Salomona3b45d42016-10-03 11:36:16 -04001396 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001397
Mike Reed7627fa52017-02-08 10:07:53 -05001398 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001399
Mike Reed20800c82017-11-15 16:09:04 -05001400 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1401 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001402 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001403}
1404
Mike Reedc1f77742016-12-09 09:00:50 -05001405void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001406 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001407 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001408
1409 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1410 SkRect r;
1411 if (path.isRect(&r)) {
1412 this->onClipRect(r, op, edgeStyle);
1413 return;
1414 }
1415 SkRRect rrect;
1416 if (path.isOval(&r)) {
1417 rrect.setOval(r);
1418 this->onClipRRect(rrect, op, edgeStyle);
1419 return;
1420 }
1421 if (path.isRRect(&rrect)) {
1422 this->onClipRRect(rrect, op, edgeStyle);
1423 return;
1424 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001425 }
robertphillips39f05382015-11-24 09:30:12 -08001426
1427 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001428}
1429
Mike Reedc1f77742016-12-09 09:00:50 -05001430void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001431 AutoValidateClip avc(this);
1432
Brian Salomona3b45d42016-10-03 11:36:16 -04001433 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001434
Mike Reed7627fa52017-02-08 10:07:53 -05001435 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436
Brian Salomona3b45d42016-10-03 11:36:16 -04001437 const SkPath* rasterClipPath = &path;
1438 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001439 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1440 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001441 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442}
1443
Mike Reedc1f77742016-12-09 09:00:50 -05001444void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001445 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001446 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001447}
1448
Mike Reedc1f77742016-12-09 09:00:50 -05001449void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001450 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001451
reed@google.com5c3d1472011-02-22 19:12:23 +00001452 AutoValidateClip avc(this);
1453
Mike Reed20800c82017-11-15 16:09:04 -05001454 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001455 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001456}
1457
reed@google.com819c9212011-02-23 18:56:55 +00001458#ifdef SK_DEBUG
1459void SkCanvas::validateClip() const {
1460 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001461 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001462 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001463 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001464 return;
1465 }
reed@google.com819c9212011-02-23 18:56:55 +00001466}
1467#endif
1468
Mike Reeda1361362017-03-07 09:37:29 -05001469bool SkCanvas::androidFramework_isClipAA() const {
1470 bool containsAA = false;
1471
1472 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1473
1474 return containsAA;
1475}
1476
1477class RgnAccumulator {
1478 SkRegion* fRgn;
1479public:
1480 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1481 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1482 SkIPoint origin = device->getOrigin();
1483 if (origin.x() | origin.y()) {
1484 rgn->translate(origin.x(), origin.y());
1485 }
1486 fRgn->op(*rgn, SkRegion::kUnion_Op);
1487 }
1488};
1489
1490void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1491 RgnAccumulator accum(rgn);
1492 SkRegion tmp;
1493
1494 rgn->setEmpty();
1495 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001496}
1497
reed@google.com5c3d1472011-02-22 19:12:23 +00001498///////////////////////////////////////////////////////////////////////////////
1499
reed@google.com754de5f2014-02-24 19:38:20 +00001500bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001501 return fMCRec->fRasterClip.isEmpty();
1502
1503 // TODO: should we only use the conservative answer in a recording canvas?
1504#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001505 SkBaseDevice* dev = this->getTopDevice();
1506 // if no device we return true
1507 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001508#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001509}
1510
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001511bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001512 SkBaseDevice* dev = this->getTopDevice();
1513 // if no device we return false
1514 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001515}
1516
msarettfbfa2582016-08-12 08:29:08 -07001517static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1518#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1519 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1520 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1521 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1522 return 0xF != _mm_movemask_ps(mask);
1523#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1524 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1525 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1526 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1527 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1528#else
1529 SkRect devRectAsRect;
1530 SkRect devClipAsRect;
1531 devRect.store(&devRectAsRect.fLeft);
1532 devClip.store(&devClipAsRect.fLeft);
1533 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1534#endif
1535}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001536
msarettfbfa2582016-08-12 08:29:08 -07001537// It's important for this function to not be inlined. Otherwise the compiler will share code
1538// between the fast path and the slow path, resulting in two slow paths.
1539static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1540 const SkMatrix& matrix) {
1541 SkRect deviceRect;
1542 matrix.mapRect(&deviceRect, src);
1543 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1544}
1545
1546bool SkCanvas::quickReject(const SkRect& src) const {
1547#ifdef SK_DEBUG
1548 // Verify that fDeviceClipBounds are set properly.
1549 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001550 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001551 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001552 } else {
msarettfbfa2582016-08-12 08:29:08 -07001553 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001554 }
msarettfbfa2582016-08-12 08:29:08 -07001555
msarett9637ea92016-08-18 14:03:30 -07001556 // Verify that fIsScaleTranslate is set properly.
1557 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001558#endif
1559
msarett9637ea92016-08-18 14:03:30 -07001560 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001561 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1562 }
1563
1564 // We inline the implementation of mapScaleTranslate() for the fast path.
1565 float sx = fMCRec->fMatrix.getScaleX();
1566 float sy = fMCRec->fMatrix.getScaleY();
1567 float tx = fMCRec->fMatrix.getTranslateX();
1568 float ty = fMCRec->fMatrix.getTranslateY();
1569 Sk4f scale(sx, sy, sx, sy);
1570 Sk4f trans(tx, ty, tx, ty);
1571
1572 // Apply matrix.
1573 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1574
1575 // Make sure left < right, top < bottom.
1576 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1577 Sk4f min = Sk4f::Min(ltrb, rblt);
1578 Sk4f max = Sk4f::Max(ltrb, rblt);
1579 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1580 // ARM this sequence generates the fastest (a single instruction).
1581 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1582
1583 // Check if the device rect is NaN or outside the clip.
1584 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001585}
1586
reed@google.com3b3e8952012-08-16 20:53:31 +00001587bool SkCanvas::quickReject(const SkPath& path) const {
1588 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001589}
1590
Mike Klein83c8dd92017-11-28 17:08:45 -05001591SkRect SkCanvas::getLocalClipBounds() const {
1592 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001593 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001594 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001595 }
1596
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001597 SkMatrix inverse;
1598 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001599 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001600 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001601 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001602
Mike Reed42e8c532017-01-23 14:09:13 -05001603 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001604 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001605 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001606
Mike Reedb57b9312018-04-23 12:12:54 -04001607 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001608 inverse.mapRect(&bounds, r);
1609 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001610}
1611
Mike Klein83c8dd92017-11-28 17:08:45 -05001612SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001613 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001614}
1615
reed@android.com8a1c16f2008-12-17 15:59:43 +00001616const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001617 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001618}
1619
Brian Osman11052242016-10-27 14:47:55 -04001620GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001621 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001622 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001623}
1624
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001625GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001626 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001627 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001628}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001629
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001630void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1631 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001632 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001633 if (outer.isEmpty()) {
1634 return;
1635 }
1636 if (inner.isEmpty()) {
1637 this->drawRRect(outer, paint);
1638 return;
1639 }
1640
1641 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001642 // be able to return ...
1643 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001644 //
1645 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001646 if (!outer.getBounds().contains(inner.getBounds())) {
1647 return;
1648 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001649
1650 this->onDrawDRRect(outer, inner, paint);
1651}
1652
reed41af9662015-01-05 07:49:08 -08001653void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001654 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001655 this->onDrawPaint(paint);
1656}
1657
1658void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001659 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001660 // To avoid redundant logic in our culling code and various backends, we always sort rects
1661 // before passing them along.
1662 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001663}
1664
msarettdca352e2016-08-26 06:37:45 -07001665void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001666 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001667 if (region.isEmpty()) {
1668 return;
1669 }
1670
1671 if (region.isRect()) {
1672 return this->drawIRect(region.getBounds(), paint);
1673 }
1674
1675 this->onDrawRegion(region, paint);
1676}
1677
reed41af9662015-01-05 07:49:08 -08001678void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001679 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001680 // To avoid redundant logic in our culling code and various backends, we always sort rects
1681 // before passing them along.
1682 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001683}
1684
1685void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001686 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001687 this->onDrawRRect(rrect, paint);
1688}
1689
1690void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001691 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001692 this->onDrawPoints(mode, count, pts, paint);
1693}
1694
Mike Reede88a1cb2017-03-17 09:50:46 -04001695void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1696 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001697 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001698 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001699 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1700 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Mike Reede88a1cb2017-03-17 09:50:46 -04001701 this->onDrawVerticesObject(vertices.get(), mode, paint);
1702}
1703
1704void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001705 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001706 RETURN_ON_NULL(vertices);
1707 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001708}
1709
1710void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001711 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001712 this->onDrawPath(path, paint);
1713}
1714
reeda85d4d02015-05-06 12:56:48 -07001715void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001716 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001717 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001718 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001719}
1720
Mike Reedc4e31092018-01-30 11:15:27 -05001721// Returns true if the rect can be "filled" : non-empty and finite
1722static bool fillable(const SkRect& r) {
1723 SkScalar w = r.width();
1724 SkScalar h = r.height();
1725 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1726}
1727
reede47829b2015-08-06 10:02:53 -07001728void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1729 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001730 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001731 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001732 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001733 return;
1734 }
1735 this->onDrawImageRect(image, &src, dst, paint, constraint);
1736}
reed41af9662015-01-05 07:49:08 -08001737
reed84984ef2015-07-17 07:09:43 -07001738void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1739 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001740 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001741 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001742}
1743
reede47829b2015-08-06 10:02:53 -07001744void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1745 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001746 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001747 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1748 constraint);
1749}
reede47829b2015-08-06 10:02:53 -07001750
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001751namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001752class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001753public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001754 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1755 if (!origPaint) {
1756 return;
1757 }
1758 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1759 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1760 }
1761 if (origPaint->getMaskFilter()) {
1762 fPaint.writable()->setMaskFilter(nullptr);
1763 }
1764 if (origPaint->isAntiAlias()) {
1765 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001766 }
1767 }
1768
1769 const SkPaint* get() const {
1770 return fPaint;
1771 }
1772
1773private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001774 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001775};
1776} // namespace
1777
reed4c21dc52015-06-25 12:32:03 -07001778void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1779 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001780 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001781 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001782 if (dst.isEmpty()) {
1783 return;
1784 }
msarett552bca92016-08-03 06:53:26 -07001785 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001786 LatticePaint latticePaint(paint);
1787 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001788 } else {
reede47829b2015-08-06 10:02:53 -07001789 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001790 }
reed4c21dc52015-06-25 12:32:03 -07001791}
1792
msarett16882062016-08-16 09:31:08 -07001793void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1794 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001795 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001796 RETURN_ON_NULL(image);
1797 if (dst.isEmpty()) {
1798 return;
1799 }
msarett71df2d72016-09-30 12:41:42 -07001800
1801 SkIRect bounds;
1802 Lattice latticePlusBounds = lattice;
1803 if (!latticePlusBounds.fBounds) {
1804 bounds = SkIRect::MakeWH(image->width(), image->height());
1805 latticePlusBounds.fBounds = &bounds;
1806 }
1807
1808 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001809 LatticePaint latticePaint(paint);
1810 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001811 } else {
1812 this->drawImageRect(image, dst, paint);
1813 }
1814}
1815
reed41af9662015-01-05 07:49:08 -08001816void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001817 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001818 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001819 return;
1820 }
reed41af9662015-01-05 07:49:08 -08001821 this->onDrawBitmap(bitmap, dx, dy, paint);
1822}
1823
reede47829b2015-08-06 10:02:53 -07001824void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001825 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001826 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001827 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001828 return;
1829 }
reede47829b2015-08-06 10:02:53 -07001830 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001831}
1832
reed84984ef2015-07-17 07:09:43 -07001833void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1834 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001835 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001836}
1837
reede47829b2015-08-06 10:02:53 -07001838void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1839 SrcRectConstraint constraint) {
1840 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1841 constraint);
1842}
reede47829b2015-08-06 10:02:53 -07001843
reed41af9662015-01-05 07:49:08 -08001844void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1845 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001846 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001847 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001848 return;
1849 }
msarett552bca92016-08-03 06:53:26 -07001850 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001851 LatticePaint latticePaint(paint);
1852 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001853 } else {
reeda5517e22015-07-14 10:54:12 -07001854 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001855 }
reed41af9662015-01-05 07:49:08 -08001856}
1857
msarettc573a402016-08-02 08:05:56 -07001858void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1859 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001860 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001861 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001862 return;
1863 }
msarett71df2d72016-09-30 12:41:42 -07001864
1865 SkIRect bounds;
1866 Lattice latticePlusBounds = lattice;
1867 if (!latticePlusBounds.fBounds) {
1868 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1869 latticePlusBounds.fBounds = &bounds;
1870 }
1871
1872 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001873 LatticePaint latticePaint(paint);
1874 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001875 } else {
msarett16882062016-08-16 09:31:08 -07001876 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001877 }
msarettc573a402016-08-02 08:05:56 -07001878}
1879
reed71c3c762015-06-24 10:29:17 -07001880void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001881 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001882 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001883 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001884 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001885 if (count <= 0) {
1886 return;
1887 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001888 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001889 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001890 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001891}
1892
reedf70b5312016-03-04 16:36:20 -08001893void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001894 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001895 if (key) {
1896 this->onDrawAnnotation(rect, key, value);
1897 }
1898}
1899
reede47829b2015-08-06 10:02:53 -07001900void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1901 const SkPaint* paint, SrcRectConstraint constraint) {
1902 if (src) {
1903 this->drawImageRect(image, *src, dst, paint, constraint);
1904 } else {
1905 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1906 dst, paint, constraint);
1907 }
1908}
1909void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1910 const SkPaint* paint, SrcRectConstraint constraint) {
1911 if (src) {
1912 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1913 } else {
1914 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1915 dst, paint, constraint);
1916 }
1917}
1918
Mike Reed4204da22017-05-17 08:53:36 -04001919void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001920 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001921 this->onDrawShadowRec(path, rec);
1922}
1923
1924void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1925 SkPaint paint;
1926 const SkRect& pathBounds = path.getBounds();
1927
1928 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1929 while (iter.next()) {
1930 iter.fDevice->drawShadow(path, rec);
1931 }
1932 LOOPER_END
1933}
1934
reed@android.com8a1c16f2008-12-17 15:59:43 +00001935//////////////////////////////////////////////////////////////////////////////
1936// These are the virtual drawing methods
1937//////////////////////////////////////////////////////////////////////////////
1938
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001939void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001940 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001941 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1942 }
1943}
1944
reed41af9662015-01-05 07:49:08 -08001945void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001946 this->internalDrawPaint(paint);
1947}
1948
1949void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001950 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001951
1952 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001953 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001954 }
1955
reed@google.com4e2b3d32011-04-07 14:18:59 +00001956 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001957}
1958
reed41af9662015-01-05 07:49:08 -08001959void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1960 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001961 if ((long)count <= 0) {
1962 return;
1963 }
1964
Mike Reed822128b2017-02-28 16:41:03 -05001965 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001966 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001967 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001968 // special-case 2 points (common for drawing a single line)
1969 if (2 == count) {
1970 r.set(pts[0], pts[1]);
1971 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001972 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001973 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001974 if (!r.isFinite()) {
1975 return;
1976 }
Mike Reed822128b2017-02-28 16:41:03 -05001977 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001978 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1979 return;
1980 }
1981 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001982 }
reed@google.coma584aed2012-05-16 14:06:02 +00001983
halcanary96fcdcc2015-08-27 07:41:13 -07001984 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001985
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001986 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001987
reed@android.com8a1c16f2008-12-17 15:59:43 +00001988 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001989 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001990 }
reed@google.com4b226022011-01-11 18:32:13 +00001991
reed@google.com4e2b3d32011-04-07 14:18:59 +00001992 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001993}
1994
reed4a167172016-08-18 17:15:25 -07001995static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1996 return ((intptr_t)paint.getImageFilter() |
1997#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1998 (intptr_t)canvas->getDrawFilter() |
1999#endif
2000 (intptr_t)paint.getLooper() ) != 0;
2001}
2002
reed41af9662015-01-05 07:49:08 -08002003void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002004 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002005 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002006 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002007 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002008 return;
2009 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002010 }
reed@google.com4b226022011-01-11 18:32:13 +00002011
reed4a167172016-08-18 17:15:25 -07002012 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002013 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002014
reed4a167172016-08-18 17:15:25 -07002015 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002016 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002017 }
2018
2019 LOOPER_END
2020 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002021 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002022 SkDrawIter iter(this);
2023 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002024 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002025 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002026 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002027}
2028
msarett44df6512016-08-25 13:54:30 -07002029void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002030 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002031 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002032 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002033 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2034 return;
2035 }
msarett44df6512016-08-25 13:54:30 -07002036 }
2037
Mike Reed822128b2017-02-28 16:41:03 -05002038 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002039
2040 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002041 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002042 }
2043
2044 LOOPER_END
2045}
2046
reed41af9662015-01-05 07:49:08 -08002047void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002048 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002049 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002050 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002051 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002052 return;
2053 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002054 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002055
Mike Reed822128b2017-02-28 16:41:03 -05002056 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002057
2058 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002059 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002060 }
2061
2062 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002063}
2064
bsalomonac3aa242016-08-19 11:25:19 -07002065void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2066 SkScalar sweepAngle, bool useCenter,
2067 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002068 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002069 if (paint.canComputeFastBounds()) {
2070 SkRect storage;
2071 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002072 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002073 return;
2074 }
bsalomonac3aa242016-08-19 11:25:19 -07002075 }
2076
Mike Reed822128b2017-02-28 16:41:03 -05002077 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002078
2079 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002080 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002081 }
2082
2083 LOOPER_END
2084}
2085
reed41af9662015-01-05 07:49:08 -08002086void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002087 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002088 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002089 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2090 return;
2091 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002092 }
2093
2094 if (rrect.isRect()) {
2095 // call the non-virtual version
2096 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002097 return;
2098 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002099 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002100 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2101 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002102 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002103
Mike Reed822128b2017-02-28 16:41:03 -05002104 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002105
2106 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002107 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002108 }
2109
2110 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002111}
2112
Mike Reed822128b2017-02-28 16:41:03 -05002113void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002114 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002115 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002116 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2117 return;
2118 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002119 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002120
Mike Reed822128b2017-02-28 16:41:03 -05002121 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002122
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002123 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002124 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002125 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002126
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002127 LOOPER_END
2128}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002129
reed41af9662015-01-05 07:49:08 -08002130void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002131 if (!path.isFinite()) {
2132 return;
2133 }
2134
Mike Reed822128b2017-02-28 16:41:03 -05002135 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002136 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002137 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002138 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2139 return;
2140 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002141 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002142
Mike Reed822128b2017-02-28 16:41:03 -05002143 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002144 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002145 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002146 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002147 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002148 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002149
Mike Reed822128b2017-02-28 16:41:03 -05002150 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151
2152 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002153 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002154 }
2155
reed@google.com4e2b3d32011-04-07 14:18:59 +00002156 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002157}
2158
reed262a71b2015-12-05 13:07:27 -08002159bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002160 if (!paint.getImageFilter()) {
2161 return false;
2162 }
2163
2164 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002165 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002166 return false;
2167 }
2168
2169 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2170 // Once we can filter and the filter will return a result larger than itself, we should be
2171 // able to remove this constraint.
2172 // skbug.com/4526
2173 //
2174 SkPoint pt;
2175 ctm.mapXY(x, y, &pt);
2176 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2177 return ir.contains(fMCRec->fRasterClip.getBounds());
2178}
2179
Mike Reedf441cfc2018-04-11 14:50:16 -04002180// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2181// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2182// null.
2183static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2184 if (paintParam) {
2185 *real = *paintParam;
2186 real->setStyle(SkPaint::kFill_Style);
2187 real->setPathEffect(nullptr);
2188 paintParam = real;
2189 }
2190 return paintParam;
2191}
2192
reeda85d4d02015-05-06 12:56:48 -07002193void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002194 SkPaint realPaint;
2195 paint = init_image_paint(&realPaint, paint);
2196
reeda85d4d02015-05-06 12:56:48 -07002197 SkRect bounds = SkRect::MakeXYWH(x, y,
2198 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002199 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002200 SkRect tmp = bounds;
2201 if (paint) {
2202 paint->computeFastBounds(tmp, &tmp);
2203 }
2204 if (this->quickReject(tmp)) {
2205 return;
2206 }
reeda85d4d02015-05-06 12:56:48 -07002207 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002208 // At this point we need a real paint object. If the caller passed null, then we should
2209 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2210 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2211 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002212
reeda2217ef2016-07-20 06:04:34 -07002213 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002214 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2215 *paint);
2216 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002217 special = this->getDevice()->makeSpecial(image);
2218 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002219 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002220 }
2221 }
2222
reed262a71b2015-12-05 13:07:27 -08002223 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2224
reeda85d4d02015-05-06 12:56:48 -07002225 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002226 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002227 if (special) {
2228 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002229 iter.fDevice->ctm().mapXY(x, y, &pt);
2230 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002231 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002232 SkScalarRoundToInt(pt.fY), pnt,
2233 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002234 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002235 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002236 }
reeda85d4d02015-05-06 12:56:48 -07002237 }
halcanary9d524f22016-03-29 09:03:52 -07002238
reeda85d4d02015-05-06 12:56:48 -07002239 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002240}
2241
reed41af9662015-01-05 07:49:08 -08002242void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002243 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002244 SkPaint realPaint;
2245 paint = init_image_paint(&realPaint, paint);
2246
halcanary96fcdcc2015-08-27 07:41:13 -07002247 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002248 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002249 if (paint) {
2250 paint->computeFastBounds(dst, &storage);
2251 }
2252 if (this->quickReject(storage)) {
2253 return;
2254 }
reeda85d4d02015-05-06 12:56:48 -07002255 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002256 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002257
senorblancoc41e7e12015-12-07 12:51:30 -08002258 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002259 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002260
reeda85d4d02015-05-06 12:56:48 -07002261 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002262 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002263 }
halcanary9d524f22016-03-29 09:03:52 -07002264
reeda85d4d02015-05-06 12:56:48 -07002265 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002266}
2267
reed41af9662015-01-05 07:49:08 -08002268void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002269 SkDEBUGCODE(bitmap.validate();)
2270
reed33366972015-10-08 09:22:02 -07002271 if (bitmap.drawsNothing()) {
2272 return;
2273 }
2274
Mike Reedf441cfc2018-04-11 14:50:16 -04002275 SkPaint realPaint;
2276 init_image_paint(&realPaint, paint);
2277 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002278
Mike Reed822128b2017-02-28 16:41:03 -05002279 SkRect bounds;
2280 bitmap.getBounds(&bounds);
2281 bounds.offset(x, y);
2282 bool canFastBounds = paint->canComputeFastBounds();
2283 if (canFastBounds) {
2284 SkRect storage;
2285 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002286 return;
2287 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002288 }
reed@google.com4b226022011-01-11 18:32:13 +00002289
reeda2217ef2016-07-20 06:04:34 -07002290 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002291 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2292 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002293 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002294 special = this->getDevice()->makeSpecial(bitmap);
2295 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002296 drawAsSprite = false;
2297 }
2298 }
2299
Mike Reed822128b2017-02-28 16:41:03 -05002300 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002301
2302 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002303 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002304 if (special) {
reed262a71b2015-12-05 13:07:27 -08002305 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002306 iter.fDevice->ctm().mapXY(x, y, &pt);
2307 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002308 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002309 SkScalarRoundToInt(pt.fY), pnt,
2310 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002311 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002312 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002313 }
reed33366972015-10-08 09:22:02 -07002314 }
msarettfbfa2582016-08-12 08:29:08 -07002315
reed33366972015-10-08 09:22:02 -07002316 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002317}
2318
reed@google.com9987ec32011-09-07 11:57:52 +00002319// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002320void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002321 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002322 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002323 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 return;
2325 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002326
halcanary96fcdcc2015-08-27 07:41:13 -07002327 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002328 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002329 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2330 return;
2331 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002332 }
reed@google.com3d608122011-11-21 15:16:16 +00002333
reed@google.com33535f32012-09-25 15:37:50 +00002334 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002335 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002336 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002337 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002338
senorblancoc41e7e12015-12-07 12:51:30 -08002339 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002340 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002341
reed@google.com33535f32012-09-25 15:37:50 +00002342 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002343 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002344 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002345
reed@google.com33535f32012-09-25 15:37:50 +00002346 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002347}
2348
reed41af9662015-01-05 07:49:08 -08002349void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002350 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002351 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002352 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002353}
2354
reed4c21dc52015-06-25 12:32:03 -07002355void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2356 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002357 SkPaint realPaint;
2358 paint = init_image_paint(&realPaint, paint);
2359
halcanary96fcdcc2015-08-27 07:41:13 -07002360 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002361 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002362 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2363 return;
2364 }
reed@google.com3d608122011-11-21 15:16:16 +00002365 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002366 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002367
senorblancoc41e7e12015-12-07 12:51:30 -08002368 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002369
reed4c21dc52015-06-25 12:32:03 -07002370 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002371 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002372 }
halcanary9d524f22016-03-29 09:03:52 -07002373
reed4c21dc52015-06-25 12:32:03 -07002374 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002375}
2376
reed41af9662015-01-05 07:49:08 -08002377void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2378 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002379 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002380 SkPaint realPaint;
2381 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002382
halcanary96fcdcc2015-08-27 07:41:13 -07002383 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002384 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002385 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2386 return;
2387 }
reed4c21dc52015-06-25 12:32:03 -07002388 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002389 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002390
senorblancoc41e7e12015-12-07 12:51:30 -08002391 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002392
reed4c21dc52015-06-25 12:32:03 -07002393 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002394 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002395 }
halcanary9d524f22016-03-29 09:03:52 -07002396
reed4c21dc52015-06-25 12:32:03 -07002397 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002398}
2399
msarett16882062016-08-16 09:31:08 -07002400void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2401 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002402 SkPaint realPaint;
2403 paint = init_image_paint(&realPaint, paint);
2404
msarett16882062016-08-16 09:31:08 -07002405 if (nullptr == paint || paint->canComputeFastBounds()) {
2406 SkRect storage;
2407 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2408 return;
2409 }
2410 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002411 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002412
2413 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2414
2415 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002416 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002417 }
2418
2419 LOOPER_END
2420}
2421
2422void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2423 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002424 SkPaint realPaint;
2425 paint = init_image_paint(&realPaint, paint);
2426
msarett16882062016-08-16 09:31:08 -07002427 if (nullptr == paint || paint->canComputeFastBounds()) {
2428 SkRect storage;
2429 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2430 return;
2431 }
2432 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002433 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002434
2435 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2436
2437 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002438 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002439 }
2440
2441 LOOPER_END
2442}
2443
reed@google.come0d9ce82014-04-23 04:00:17 +00002444void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2445 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002446
halcanary96fcdcc2015-08-27 07:41:13 -07002447 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002448
2449 while (iter.next()) {
Herb Derby41f4f312018-06-06 17:45:53 +00002450 auto glyphRun = SkGlyphRun::MakeFromDrawText(
2451 looper.paint(), text, byteLength, SkPoint::Make(x, y));
2452 iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002453 }
2454
reed@google.com4e2b3d32011-04-07 14:18:59 +00002455 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002456}
2457
reed@google.come0d9ce82014-04-23 04:00:17 +00002458void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2459 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002460
halcanary96fcdcc2015-08-27 07:41:13 -07002461 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002462
reed@android.com8a1c16f2008-12-17 15:59:43 +00002463 while (iter.next()) {
Herb Derby41f4f312018-06-06 17:45:53 +00002464 auto glyphRun = SkGlyphRun::MakeFromDrawPosText(looper.paint(), text, byteLength, pos);
2465 iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002467
reed@google.com4e2b3d32011-04-07 14:18:59 +00002468 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002469}
2470
reed@google.come0d9ce82014-04-23 04:00:17 +00002471void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2472 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002473
halcanary96fcdcc2015-08-27 07:41:13 -07002474 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002475
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476 while (iter.next()) {
Herb Derby41f4f312018-06-06 17:45:53 +00002477 auto glyphRun =
2478 SkGlyphRun::MakeFromDrawPosTextH(looper.paint(), text, byteLength, xpos, constY);
2479 iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002481
reed@google.com4e2b3d32011-04-07 14:18:59 +00002482 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002483}
2484
reed@google.come0d9ce82014-04-23 04:00:17 +00002485void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2486 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002487 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002488
reed@android.com8a1c16f2008-12-17 15:59:43 +00002489 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002490 iter.fDevice->drawTextOnPath(text, byteLength, path, matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002491 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002492
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002493 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002494}
2495
reed45561a02016-07-07 12:47:17 -07002496void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2497 const SkRect* cullRect, const SkPaint& paint) {
2498 if (cullRect && this->quickReject(*cullRect)) {
2499 return;
2500 }
2501
2502 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2503
2504 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002505 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002506 }
2507
2508 LOOPER_END
2509}
2510
fmalita00d5c2c2014-08-21 08:53:26 -07002511void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2512 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002513 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002514 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002515 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002516 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002517 SkRect tmp;
2518 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2519 return;
2520 }
2521 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002522 }
2523
fmalita024f9962015-03-03 19:08:17 -08002524 // We cannot filter in the looper as we normally do, because the paint is
2525 // incomplete at this point (text-related attributes are embedded within blob run paints).
2526 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002527 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002528
fmalita85d5eb92015-03-04 11:20:12 -08002529 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002530
fmalitaaa1b9122014-08-28 14:32:24 -07002531 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002532 iter.fDevice->drawTextBlob(blob, x, y, looper.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002533 }
2534
fmalitaaa1b9122014-08-28 14:32:24 -07002535 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002536
2537 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002538}
2539
Cary Clark2a475ea2017-04-28 15:35:12 -04002540void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2541 this->drawText(string.c_str(), string.size(), x, y, paint);
2542}
2543
reed@google.come0d9ce82014-04-23 04:00:17 +00002544// These will become non-virtual, so they always call the (virtual) onDraw... method
2545void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2546 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002547 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002548 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002549 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002550 this->onDrawText(text, byteLength, x, y, paint);
2551 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002552}
2553void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2554 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002555 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002556 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002557 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002558 this->onDrawPosText(text, byteLength, pos, paint);
2559 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002560}
2561void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2562 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002563 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002564 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002565 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002566 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2567 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002568}
2569void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2570 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002571 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002572 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002573 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002574 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2575 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002576}
reed45561a02016-07-07 12:47:17 -07002577void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2578 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002579 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002580 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002581 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002582 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2583 }
2584}
fmalita00d5c2c2014-08-21 08:53:26 -07002585void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2586 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002587 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002588 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002589 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002590 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002591}
reed@google.come0d9ce82014-04-23 04:00:17 +00002592
Mike Reede88a1cb2017-03-17 09:50:46 -04002593void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2594 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002595 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2596
2597 while (iter.next()) {
2598 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002599 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002600 }
2601
2602 LOOPER_END
2603}
2604
dandovb3c9d1c2014-08-12 08:34:29 -07002605void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002606 const SkPoint texCoords[4], SkBlendMode bmode,
2607 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002608 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002609 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002610 return;
2611 }
mtklein6cfa73a2014-08-13 13:33:49 -07002612
Mike Reedfaba3712016-11-03 14:45:31 -04002613 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002614}
2615
2616void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002617 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002618 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002619 // Since a patch is always within the convex hull of the control points, we discard it when its
2620 // bounding rectangle is completely outside the current clip.
2621 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002622 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002623 if (this->quickReject(bounds)) {
2624 return;
2625 }
mtklein6cfa73a2014-08-13 13:33:49 -07002626
Mike Reed435071e2017-05-23 11:22:56 -04002627 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2628
halcanary96fcdcc2015-08-27 07:41:13 -07002629 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002630
dandovecfff212014-08-04 10:02:00 -07002631 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002632 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002633 }
mtklein6cfa73a2014-08-13 13:33:49 -07002634
dandovecfff212014-08-04 10:02:00 -07002635 LOOPER_END
2636}
2637
reeda8db7282015-07-07 10:22:31 -07002638void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002639#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002640 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002641#endif
reede3b38ce2016-01-08 09:18:44 -08002642 RETURN_ON_NULL(dr);
2643 if (x || y) {
2644 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2645 this->onDrawDrawable(dr, &matrix);
2646 } else {
2647 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002648 }
2649}
2650
reeda8db7282015-07-07 10:22:31 -07002651void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002652#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002653 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002654#endif
reede3b38ce2016-01-08 09:18:44 -08002655 RETURN_ON_NULL(dr);
2656 if (matrix && matrix->isIdentity()) {
2657 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002658 }
reede3b38ce2016-01-08 09:18:44 -08002659 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002660}
2661
2662void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002663 // drawable bounds are no longer reliable (e.g. android displaylist)
2664 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002665 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002666}
2667
reed71c3c762015-06-24 10:29:17 -07002668void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002669 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002670 const SkRect* cull, const SkPaint* paint) {
2671 if (cull && this->quickReject(*cull)) {
2672 return;
2673 }
2674
2675 SkPaint pnt;
2676 if (paint) {
2677 pnt = *paint;
2678 }
halcanary9d524f22016-03-29 09:03:52 -07002679
halcanary96fcdcc2015-08-27 07:41:13 -07002680 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002681 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002682 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002683 }
2684 LOOPER_END
2685}
2686
reedf70b5312016-03-04 16:36:20 -08002687void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2688 SkASSERT(key);
2689
2690 SkPaint paint;
2691 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2692 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002693 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002694 }
2695 LOOPER_END
2696}
2697
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698//////////////////////////////////////////////////////////////////////////////
2699// These methods are NOT virtual, and therefore must call back into virtual
2700// methods, rather than actually drawing themselves.
2701//////////////////////////////////////////////////////////////////////////////
2702
reed374772b2016-10-05 17:33:02 -07002703void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002704 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002705 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002706 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002707 this->drawPaint(paint);
2708}
2709
2710void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002711 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002712 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2713}
2714
Mike Reed3661bc92017-02-22 13:21:42 -05002715void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002717 pts[0].set(x0, y0);
2718 pts[1].set(x1, y1);
2719 this->drawPoints(kLines_PointMode, 2, pts, paint);
2720}
2721
Mike Reed3661bc92017-02-22 13:21:42 -05002722void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 if (radius < 0) {
2724 radius = 0;
2725 }
2726
2727 SkRect r;
2728 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002729 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730}
2731
2732void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2733 const SkPaint& paint) {
2734 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002735 SkRRect rrect;
2736 rrect.setRectXY(r, rx, ry);
2737 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002738 } else {
2739 this->drawRect(r, paint);
2740 }
2741}
2742
reed@android.com8a1c16f2008-12-17 15:59:43 +00002743void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2744 SkScalar sweepAngle, bool useCenter,
2745 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002746 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002747 if (oval.isEmpty() || !sweepAngle) {
2748 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002749 }
bsalomon21af9ca2016-08-25 12:29:23 -07002750 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751}
2752
2753void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2754 const SkPath& path, SkScalar hOffset,
2755 SkScalar vOffset, const SkPaint& paint) {
2756 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002757
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758 matrix.setTranslate(hOffset, vOffset);
2759 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2760}
2761
reed@android.comf76bacf2009-05-13 14:00:33 +00002762///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002763
Mike Klein88d90712018-01-27 17:30:04 +00002764/**
2765 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2766 * against the playback cost of recursing into the subpicture to get at its actual ops.
2767 *
2768 * For now we pick a conservatively small value, though measurement (and other heuristics like
2769 * the type of ops contained) may justify changing this value.
2770 */
2771#define kMaxPictureOpsToUnrollInsteadOfRef 1
2772
reedd5fa1a42014-08-09 11:08:05 -07002773void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002774 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002775 RETURN_ON_NULL(picture);
2776
reede3b38ce2016-01-08 09:18:44 -08002777 if (matrix && matrix->isIdentity()) {
2778 matrix = nullptr;
2779 }
Mike Klein88d90712018-01-27 17:30:04 +00002780 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2781 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2782 picture->playback(this);
2783 } else {
2784 this->onDrawPicture(picture, matrix, paint);
2785 }
reedd5fa1a42014-08-09 11:08:05 -07002786}
robertphillips9b14f262014-06-04 05:40:44 -07002787
reedd5fa1a42014-08-09 11:08:05 -07002788void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2789 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002790 if (!paint || paint->canComputeFastBounds()) {
2791 SkRect bounds = picture->cullRect();
2792 if (paint) {
2793 paint->computeFastBounds(bounds, &bounds);
2794 }
2795 if (matrix) {
2796 matrix->mapRect(&bounds);
2797 }
2798 if (this->quickReject(bounds)) {
2799 return;
2800 }
2801 }
2802
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002803 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002804 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805}
2806
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807///////////////////////////////////////////////////////////////////////////////
2808///////////////////////////////////////////////////////////////////////////////
2809
reed3aafe112016-08-18 12:45:34 -07002810SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002811 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812
2813 SkASSERT(canvas);
2814
reed3aafe112016-08-18 12:45:34 -07002815 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816 fDone = !fImpl->next();
2817}
2818
2819SkCanvas::LayerIter::~LayerIter() {
2820 fImpl->~SkDrawIter();
2821}
2822
2823void SkCanvas::LayerIter::next() {
2824 fDone = !fImpl->next();
2825}
2826
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002827SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002828 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002829}
2830
2831const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002832 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833}
2834
2835const SkPaint& SkCanvas::LayerIter::paint() const {
2836 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002837 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002838 paint = &fDefaultPaint;
2839 }
2840 return *paint;
2841}
2842
Mike Reedca37f322018-03-08 13:22:16 -05002843SkIRect SkCanvas::LayerIter::clipBounds() const {
2844 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002845}
2846
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2848int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002849
2850///////////////////////////////////////////////////////////////////////////////
2851
Brian Osman10fc6fd2018-03-02 11:01:10 -05002852// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002853static bool supported_for_raster_canvas(const SkImageInfo& info) {
2854 switch (info.alphaType()) {
2855 case kPremul_SkAlphaType:
2856 case kOpaque_SkAlphaType:
2857 break;
2858 default:
2859 return false;
2860 }
2861
2862 switch (info.colorType()) {
2863 case kAlpha_8_SkColorType:
2864 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002865 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002866 case kRGBA_F16_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002867 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002868 break;
2869 default:
2870 return false;
2871 }
2872
2873 return true;
2874}
2875
Mike Reed5df49342016-11-12 08:06:55 -06002876std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002877 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002878 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002879 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002880 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002881
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002882 SkBitmap bitmap;
2883 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002884 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002885 }
Mike Reed12f77342017-11-08 11:19:52 -05002886
2887 return props ?
2888 skstd::make_unique<SkCanvas>(bitmap, *props) :
2889 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002890}
reedd5fa1a42014-08-09 11:08:05 -07002891
2892///////////////////////////////////////////////////////////////////////////////
2893
Florin Malitaee424ac2016-12-01 12:47:59 -05002894SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2895 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2896
Florin Malita439ace92016-12-02 12:05:41 -05002897SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2898 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2899
Herb Derbyefe39bc2018-05-01 17:06:20 -04002900SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002901 : INHERITED(device) {}
2902
Florin Malitaee424ac2016-12-01 12:47:59 -05002903SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2904 (void)this->INHERITED::getSaveLayerStrategy(rec);
2905 return kNoLayer_SaveLayerStrategy;
2906}
2907
2908///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002909
reed73603f32016-09-20 08:42:38 -07002910static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2911static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2912static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2913static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2914static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2915static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002916
2917///////////////////////////////////////////////////////////////////////////////////////////////////
2918
2919SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2920 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002921 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002922 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2923 SkIPoint origin = dev->getOrigin();
2924 SkMatrix ctm = this->getTotalMatrix();
2925 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2926
2927 SkIRect clip = fMCRec->fRasterClip.getBounds();
2928 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002929 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002930 clip.setEmpty();
2931 }
2932
2933 fAllocator->updateHandle(handle, ctm, clip);
2934 return handle;
2935 }
2936 return nullptr;
2937}
2938
2939static bool install(SkBitmap* bm, const SkImageInfo& info,
2940 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002941 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002942}
2943
2944SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2945 SkBitmap* bm) {
2946 SkRasterHandleAllocator::Rec rec;
2947 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2948 return nullptr;
2949 }
2950 return rec.fHandle;
2951}
2952
2953std::unique_ptr<SkCanvas>
2954SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2955 const SkImageInfo& info, const Rec* rec) {
2956 if (!alloc || !supported_for_raster_canvas(info)) {
2957 return nullptr;
2958 }
2959
2960 SkBitmap bm;
2961 Handle hndl;
2962
2963 if (rec) {
2964 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2965 } else {
2966 hndl = alloc->allocBitmap(info, &bm);
2967 }
2968 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2969}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002970
2971///////////////////////////////////////////////////////////////////////////////////////////////////
2972
2973