blob: 494bd3b837eb465c8592031f9ab065d715658c1e [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Hal Canaryc640d0d2018-06-13 09:59:02 -04008#include "SkCanvas.h"
9
Herb Derby73fe7b02017-02-08 15:12:19 -050010#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +000011#include "SkBitmapDevice.h"
reedd5fa1a42014-08-09 11:08:05 -070012#include "SkCanvasPriv.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040013#include "SkClipOpPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070014#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070015#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDraw.h"
17#include "SkDrawFilter.h"
18#include "SkDrawLooper.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040019#include "SkDrawable.h"
Herb Derby41f4f312018-06-06 17:45:53 +000020#include "SkGlyphCache.h"
21#include "SkGlyphRun.h"
piotaixrb5fae932014-09-24 13:03:30 -070022#include "SkImage.h"
senorblanco900c3672016-04-27 11:31:23 -070023#include "SkImageFilter.h"
24#include "SkImageFilterCache.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040025#include "SkImage_Base.h"
msarettc573a402016-08-02 08:05:56 -070026#include "SkLatticeIter.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040027#include "SkMSAN.h"
Mike Reed5df49342016-11-12 08:06:55 -060028#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080029#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000030#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050031#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070032#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070033#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070034#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040035#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000036#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040037#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000038#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050039#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080040#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000041#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040042#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000043#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040044#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070045#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000046#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040047#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080048#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040049#include "SkVertices.h"
50
bungemand3ebb482015-08-05 13:57:49 -070051#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000052
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080054#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050055#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000056#endif
57
reede3b38ce2016-01-08 09:18:44 -080058#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050059#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080060
Mike Reed139e5e02017-03-08 11:29:33 -050061///////////////////////////////////////////////////////////////////////////////////////////////////
62
reedc83a2972015-07-16 07:40:45 -070063/*
64 * Return true if the drawing this rect would hit every pixels in the canvas.
65 *
66 * Returns false if
67 * - rect does not contain the canvas' bounds
68 * - paint is not fill
69 * - paint would blur or otherwise change the coverage of the rect
70 */
71bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
72 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070073 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
74 (int)kNone_ShaderOverrideOpacity,
75 "need_matching_enums0");
76 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
77 (int)kOpaque_ShaderOverrideOpacity,
78 "need_matching_enums1");
79 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
80 (int)kNotOpaque_ShaderOverrideOpacity,
81 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070082
83 const SkISize size = this->getBaseLayerSize();
84 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050085
86 // if we're clipped at all, we can't overwrite the entire surface
87 {
88 SkBaseDevice* base = this->getDevice();
89 SkBaseDevice* top = this->getTopDevice();
90 if (base != top) {
91 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
92 }
93 if (!base->clipIsWideOpen()) {
94 return false;
95 }
reedc83a2972015-07-16 07:40:45 -070096 }
97
98 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070099 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700100 return false; // conservative
101 }
halcanaryc5769b22016-08-10 07:13:21 -0700102
103 SkRect devRect;
104 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
105 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700106 return false;
107 }
108 }
109
110 if (paint) {
111 SkPaint::Style paintStyle = paint->getStyle();
112 if (!(paintStyle == SkPaint::kFill_Style ||
113 paintStyle == SkPaint::kStrokeAndFill_Style)) {
114 return false;
115 }
116 if (paint->getMaskFilter() || paint->getLooper()
117 || paint->getPathEffect() || paint->getImageFilter()) {
118 return false; // conservative
119 }
120 }
121 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
122}
123
124///////////////////////////////////////////////////////////////////////////////////////////////////
125
reed@google.comda17f752012-08-16 18:27:05 +0000126// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127//#define SK_TRACE_SAVERESTORE
128
129#ifdef SK_TRACE_SAVERESTORE
130 static int gLayerCounter;
131 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
132 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
133
134 static int gRecCounter;
135 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
136 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
137
138 static int gCanvasCounter;
139 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
140 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
141#else
142 #define inc_layer()
143 #define dec_layer()
144 #define inc_rec()
145 #define dec_rec()
146 #define inc_canvas()
147 #define dec_canvas()
148#endif
149
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000150typedef SkTLazy<SkPaint> SkLazyPaint;
151
reedc83a2972015-07-16 07:40:45 -0700152void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000153 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700154 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
155 ? SkSurface::kDiscard_ContentChangeMode
156 : SkSurface::kRetain_ContentChangeMode);
157 }
158}
159
160void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
161 ShaderOverrideOpacity overrideOpacity) {
162 if (fSurfaceBase) {
163 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
164 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
165 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
166 // and therefore we don't care which mode we're in.
167 //
168 if (fSurfaceBase->outstandingImageSnapshot()) {
169 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
170 mode = SkSurface::kDiscard_ContentChangeMode;
171 }
172 }
173 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000174 }
175}
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000179/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 The clip/matrix/proc are fields that reflect the top of the save/restore
181 stack. Whenever the canvas changes, it marks a dirty flag, and then before
182 these are used (assuming we're not on a layer) we rebuild these cache
183 values: they reflect the top of the save stack, but translated and clipped
184 by the device's XY offset and bitmap-bounds.
185*/
186struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400187 DeviceCM* fNext;
188 sk_sp<SkBaseDevice> fDevice;
189 SkRasterClip fClip;
190 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
191 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400192 sk_sp<SkImage> fClipImage;
193 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194
Florin Malita53f77bd2017-04-28 13:48:37 -0400195 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000196 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700197 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400198 , fDevice(std::move(device))
199 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700200 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000201 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400202 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400203 {}
reed@google.com4b226022011-01-11 18:32:13 +0000204
mtkleinfeaadee2015-04-08 11:25:48 -0700205 void reset(const SkIRect& bounds) {
206 SkASSERT(!fPaint);
207 SkASSERT(!fNext);
208 SkASSERT(fDevice);
209 fClip.setRect(bounds);
210 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211};
212
213/* This is the record we keep for each save/restore level in the stack.
214 Since a level optionally copies the matrix and/or stack, we have pointers
215 for these fields. If the value is copied for this level, the copy is
216 stored in the ...Storage field, and the pointer points to that. If the
217 value is not copied for this level, we ignore ...Storage, and just point
218 at the corresponding value in the previous level in the stack.
219*/
220class SkCanvas::MCRec {
221public:
reed1f836ee2014-07-07 07:49:34 -0700222 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700223 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 /* If there are any layers in the stack, this points to the top-most
225 one that is at or below this level in the stack (so we know what
226 bitmap/device to draw into from this level. This value is NOT
227 reference counted, since the real owner is either our fLayer field,
228 or a previous one in a lower level.)
229 */
Mike Reeda1361362017-03-07 09:37:29 -0500230 DeviceCM* fTopLayer;
231 SkConservativeClip fRasterClip;
232 SkMatrix fMatrix;
233 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234
Mike Reeda1361362017-03-07 09:37:29 -0500235 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700236 fFilter = nullptr;
237 fLayer = nullptr;
238 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800239 fMatrix.reset();
240 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700241
reedd9544982014-09-09 18:46:22 -0700242 // don't bother initializing fNext
243 inc_rec();
244 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400245 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700246 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700247 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700248 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800249 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 // don't bother initializing fNext
252 inc_rec();
253 }
254 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000255 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700256 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 dec_rec();
258 }
mtkleinfeaadee2015-04-08 11:25:48 -0700259
260 void reset(const SkIRect& bounds) {
261 SkASSERT(fLayer);
262 SkASSERT(fDeferredSaveCount == 0);
263
264 fMatrix.reset();
265 fRasterClip.setRect(bounds);
266 fLayer->reset(bounds);
267 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268};
269
Mike Reeda1361362017-03-07 09:37:29 -0500270class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271public:
Mike Reeda1361362017-03-07 09:37:29 -0500272 SkDrawIter(SkCanvas* canvas)
273 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
274 {}
reed@google.com4b226022011-01-11 18:32:13 +0000275
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000277 const DeviceCM* rec = fCurrLayer;
278 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400279 fDevice = rec->fDevice.get();
280 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700282 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 return true;
284 }
285 return false;
286 }
reed@google.com4b226022011-01-11 18:32:13 +0000287
reed@google.com6f8f2922011-03-04 22:27:10 +0000288 int getX() const { return fDevice->getOrigin().x(); }
289 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000291
Mike Reed99330ba2017-02-22 11:01:08 -0500292 SkBaseDevice* fDevice;
293
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 const DeviceCM* fCurrLayer;
296 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297};
298
Florin Malita713b8ef2017-04-28 10:57:24 -0400299#define FOR_EACH_TOP_DEVICE( code ) \
300 do { \
301 DeviceCM* layer = fMCRec->fTopLayer; \
302 while (layer) { \
303 SkBaseDevice* device = layer->fDevice.get(); \
304 if (device) { \
305 code; \
306 } \
307 layer = layer->fNext; \
308 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500309 } while (0)
310
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311/////////////////////////////////////////////////////////////////////////////
312
reeddbc3cef2015-04-29 12:18:57 -0700313static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
314 return lazy->isValid() ? lazy->get() : lazy->set(orig);
315}
316
317/**
318 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700319 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700320 */
reedd053ce92016-03-22 10:17:23 -0700321static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700322 SkImageFilter* imgf = paint.getImageFilter();
323 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700324 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700325 }
326
reedd053ce92016-03-22 10:17:23 -0700327 SkColorFilter* imgCFPtr;
328 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700329 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700330 }
reedd053ce92016-03-22 10:17:23 -0700331 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700332
333 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700334 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700335 // there is no existing paint colorfilter, so we can just return the imagefilter's
336 return imgCF;
337 }
338
339 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
340 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500341 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700342}
343
senorblanco87e066e2015-10-28 11:23:36 -0700344/**
345 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
346 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
347 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
348 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
349 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
350 * conservative "effective" bounds based on the settings in the paint... with one exception. This
351 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
352 * deliberately ignored.
353 */
354static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
355 const SkRect& rawBounds,
356 SkRect* storage) {
357 SkPaint tmpUnfiltered(paint);
358 tmpUnfiltered.setImageFilter(nullptr);
359 if (tmpUnfiltered.canComputeFastBounds()) {
360 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
361 } else {
362 return rawBounds;
363 }
364}
365
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366class AutoDrawLooper {
367public:
senorblanco87e066e2015-10-28 11:23:36 -0700368 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
369 // paint. It's used to determine the size of the offscreen layer for filters.
370 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700371 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700372 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000373 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800374#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800376#else
377 fFilter = nullptr;
378#endif
reed4a8126e2014-09-22 07:29:03 -0700379 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000380 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700381 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000382 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383
reedd053ce92016-03-22 10:17:23 -0700384 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700385 if (simplifiedCF) {
386 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700387 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700388 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700389 fPaint = paint;
390 }
391
392 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700393 /**
394 * We implement ImageFilters for a given draw by creating a layer, then applying the
395 * imagefilter to the pixels of that layer (its backing surface/image), and then
396 * we call restore() to xfer that layer to the main canvas.
397 *
398 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
399 * 2. Generate the src pixels:
400 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
401 * return (fPaint). We then draw the primitive (using srcover) into a cleared
402 * buffer/surface.
403 * 3. Restore the layer created in #1
404 * The imagefilter is passed the buffer/surface from the layer (now filled with the
405 * src pixels of the primitive). It returns a new "filtered" buffer, which we
406 * draw onto the previous layer using the xfermode from the original paint.
407 */
reed@google.com8926b162012-03-23 15:36:36 +0000408 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500409 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700410 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700411 SkRect storage;
412 if (rawBounds) {
413 // Make rawBounds include all paint outsets except for those due to image filters.
414 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
415 }
reedbfd5f172016-01-07 11:28:08 -0800416 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700417 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700418 fTempLayerForImageFilter = true;
419 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000420 }
421
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000422 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500423 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000424 fIsSimple = false;
425 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700426 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000427 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700428 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000429 }
430 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000431
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700433 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000434 fCanvas->internalRestore();
435 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000436 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000438
reed@google.com4e2b3d32011-04-07 14:18:59 +0000439 const SkPaint& paint() const {
440 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400441 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000442 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000444
reed@google.com129ec222012-05-15 13:24:09 +0000445 bool next(SkDrawFilter::Type drawType) {
446 if (fDone) {
447 return false;
448 } else if (fIsSimple) {
449 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000450 return !fPaint->nothingToDraw();
451 } else {
452 return this->doNext(drawType);
453 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000454 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000455
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500457 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700458 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000459 SkCanvas* fCanvas;
460 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000461 SkDrawFilter* fFilter;
462 const SkPaint* fPaint;
463 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700464 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000465 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000466 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000467 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400468 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000469
470 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471};
472
reed@google.com129ec222012-05-15 13:24:09 +0000473bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700474 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000475 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700476 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000477
reeddbc3cef2015-04-29 12:18:57 -0700478 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
479 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400480 // never want our downstream clients (i.e. devices) to see loopers
481 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000482
reed5c476fb2015-04-20 08:04:21 -0700483 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700484 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700485 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000486 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000487
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000488 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000489 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000490 return false;
491 }
492 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000493 if (!fFilter->filter(paint, drawType)) {
494 fDone = true;
Mike Reed59af19f2018-04-12 17:26:40 -0400495 return false; // can we really do this, if we haven't finished fLooperContext?
reed@google.com971aca72012-11-26 20:26:54 +0000496 }
halcanary96fcdcc2015-08-27 07:41:13 -0700497 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000498 // no looper means we only draw once
499 fDone = true;
500 }
501 }
502 fPaint = paint;
503
504 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000505 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000506 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000507 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000508 return true;
509}
510
reed@android.com8a1c16f2008-12-17 15:59:43 +0000511////////// macros to place around the internal draw calls //////////////////
512
reed3aafe112016-08-18 12:45:34 -0700513#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
514 this->predrawNotify(); \
515 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
516 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800517 SkDrawIter iter(this);
518
519
reed@google.com8926b162012-03-23 15:36:36 +0000520#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000521 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700522 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000523 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000524 SkDrawIter iter(this);
525
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000526#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000527 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700528 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000529 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000531
reedc83a2972015-07-16 07:40:45 -0700532#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
533 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700534 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700535 while (looper.next(type)) { \
536 SkDrawIter iter(this);
537
reed@google.com4e2b3d32011-04-07 14:18:59 +0000538#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539
540////////////////////////////////////////////////////////////////////////////
541
msarettfbfa2582016-08-12 08:29:08 -0700542static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
543 if (bounds.isEmpty()) {
544 return SkRect::MakeEmpty();
545 }
546
547 // Expand bounds out by 1 in case we are anti-aliasing. We store the
548 // bounds as floats to enable a faster quick reject implementation.
549 SkRect dst;
550 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
551 return dst;
552}
553
mtkleinfeaadee2015-04-08 11:25:48 -0700554void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
555 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700556 fMCRec->reset(bounds);
557
558 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500559 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400560 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700561 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700562 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700563}
564
Herb Derbyefe39bc2018-05-01 17:06:20 -0400565void SkCanvas::init(sk_sp<SkBaseDevice> device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800566 if (device && device->forceConservativeRasterClip()) {
567 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
568 }
reed42b73eb2015-11-20 13:42:42 -0800569
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000570 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800571 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700572 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000573
574 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500575 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500576 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700577 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578
reeda499f902015-05-01 09:34:31 -0700579 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
580 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400581 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700582
reed@android.com8a1c16f2008-12-17 15:59:43 +0000583 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000584
halcanary96fcdcc2015-08-27 07:41:13 -0700585 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000586
reedf92c8662014-08-18 08:02:43 -0700587 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700588 // The root device and the canvas should always have the same pixel geometry
589 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800590 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700591 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500592
Mike Reedc42a1cd2017-02-14 14:25:14 -0500593 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700594 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400595
Herb Derby59d997a2018-06-07 12:44:09 -0400596 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597}
598
reed@google.comcde92112011-07-06 20:00:52 +0000599SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000600 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700601 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000602{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000603 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000604
halcanary96fcdcc2015-08-27 07:41:13 -0700605 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000606}
607
reed96a857e2015-01-25 10:33:58 -0800608SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000609 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800610 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000611{
612 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400613 this->init(sk_make_sp<SkNoPixelsDevice>(
614 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps), kDefault_InitFlags);
reedd9544982014-09-09 18:46:22 -0700615}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000616
reed78e27682014-11-19 08:04:34 -0800617SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700618 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700619 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700620{
621 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700622
Mike Reed566e53c2017-03-10 10:49:45 -0500623 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400624 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps), flags);
reedd9544982014-09-09 18:46:22 -0700625}
626
Herb Derbyefe39bc2018-05-01 17:06:20 -0400627SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000628 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700629 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000630{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000631 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700632
reedd9544982014-09-09 18:46:22 -0700633 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000634}
635
Herb Derbyefe39bc2018-05-01 17:06:20 -0400636SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device, InitFlags flags)
robertphillipsfcf78292015-06-19 11:49:52 -0700637 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700638 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700639{
640 inc_canvas();
641
642 this->init(device, flags);
643}
644
reed4a8126e2014-09-22 07:29:03 -0700645SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700646 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700647 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700648{
649 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700650
Mike Reed910ca0f2018-04-25 13:04:05 -0400651 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400652 this->init(device, kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700653}
reed29c857d2014-09-21 10:25:07 -0700654
Mike Reed356f7c22017-01-10 11:58:39 -0500655SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
656 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700657 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
658 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500659 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700660{
661 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700662
Mike Reed910ca0f2018-04-25 13:04:05 -0400663 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400664 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665}
666
Mike Reed356f7c22017-01-10 11:58:39 -0500667SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
668
Matt Sarett31f99ce2017-04-11 08:46:01 -0400669#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
670SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
671 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
672 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
673 , fAllocator(nullptr)
674{
675 inc_canvas();
676
677 SkBitmap tmp(bitmap);
678 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400679 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400680 this->init(device, kDefault_InitFlags);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400681}
682#endif
683
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684SkCanvas::~SkCanvas() {
685 // free up the contents of our deque
686 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000687
reed@android.com8a1c16f2008-12-17 15:59:43 +0000688 this->internalRestore(); // restore the last, since we're going away
689
halcanary385fe4d2015-08-26 13:07:48 -0700690 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000691
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692 dec_canvas();
693}
694
fmalita53d9f1c2016-01-25 06:23:54 -0800695#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696SkDrawFilter* SkCanvas::getDrawFilter() const {
697 return fMCRec->fFilter;
698}
699
700SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700701 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000702 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
703 return filter;
704}
fmalita77650002016-01-21 18:47:11 -0800705#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000707SkMetaData& SkCanvas::getMetaData() {
708 // metadata users are rare, so we lazily allocate it. If that changes we
709 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700710 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000711 fMetaData = new SkMetaData;
712 }
713 return *fMetaData;
714}
715
reed@android.com8a1c16f2008-12-17 15:59:43 +0000716///////////////////////////////////////////////////////////////////////////////
717
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000718void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700719 this->onFlush();
720}
721
722void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000723 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000724 if (device) {
725 device->flush();
726 }
727}
728
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000729SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000730 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000731 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
732}
733
senorblancoafc7cce2016-02-02 18:44:15 -0800734SkIRect SkCanvas::getTopLayerBounds() const {
735 SkBaseDevice* d = this->getTopDevice();
736 if (!d) {
737 return SkIRect::MakeEmpty();
738 }
739 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
740}
741
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000742SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000743 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000744 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000745 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400746 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000747}
748
Florin Malita0ed3b642017-01-13 16:56:38 +0000749SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400750 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000751}
752
Mike Reed353196f2017-07-21 11:01:18 -0400753bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000754 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400755 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000756}
757
Mike Reed353196f2017-07-21 11:01:18 -0400758bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
759 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400760}
761
762bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
763 SkPixmap pm;
764 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
765}
766
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000767bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400768 SkPixmap pm;
769 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700770 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000771 }
772 return false;
773}
774
Matt Sarett03dd6d52017-01-23 12:15:09 -0500775bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000776 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000777 SkBaseDevice* device = this->getDevice();
778 if (!device) {
779 return false;
780 }
781
Matt Sarett03dd6d52017-01-23 12:15:09 -0500782 // This check gives us an early out and prevents generation ID churn on the surface.
783 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
784 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
785 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
786 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000787 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000788
Matt Sarett03dd6d52017-01-23 12:15:09 -0500789 // Tell our owning surface to bump its generation ID.
790 const bool completeOverwrite =
791 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700792 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700793
Matt Sarett03dd6d52017-01-23 12:15:09 -0500794 // This can still fail, most notably in the case of a invalid color type or alpha type
795 // conversion. We could pull those checks into this function and avoid the unnecessary
796 // generation ID bump. But then we would be performing those checks twice, since they
797 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400798 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000799}
reed@google.com51df9e32010-12-23 19:29:18 +0000800
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801//////////////////////////////////////////////////////////////////////////////
802
reed2ff1fce2014-12-11 07:07:37 -0800803void SkCanvas::checkForDeferredSave() {
804 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800805 this->doSave();
806 }
807}
808
reedf0090cb2014-11-26 08:55:51 -0800809int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800810#ifdef SK_DEBUG
811 int count = 0;
812 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
813 for (;;) {
814 const MCRec* rec = (const MCRec*)iter.next();
815 if (!rec) {
816 break;
817 }
818 count += 1 + rec->fDeferredSaveCount;
819 }
820 SkASSERT(count == fSaveCount);
821#endif
822 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800823}
824
825int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800826 fSaveCount += 1;
827 fMCRec->fDeferredSaveCount += 1;
828 return this->getSaveCount() - 1; // return our prev value
829}
830
831void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800832 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700833
834 SkASSERT(fMCRec->fDeferredSaveCount > 0);
835 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800836 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800837}
838
839void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800840 if (fMCRec->fDeferredSaveCount > 0) {
841 SkASSERT(fSaveCount > 1);
842 fSaveCount -= 1;
843 fMCRec->fDeferredSaveCount -= 1;
844 } else {
845 // check for underflow
846 if (fMCStack.count() > 1) {
847 this->willRestore();
848 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700849 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800850 this->internalRestore();
851 this->didRestore();
852 }
reedf0090cb2014-11-26 08:55:51 -0800853 }
854}
855
856void SkCanvas::restoreToCount(int count) {
857 // sanity check
858 if (count < 1) {
859 count = 1;
860 }
mtkleinf0f14112014-12-12 08:46:25 -0800861
reedf0090cb2014-11-26 08:55:51 -0800862 int n = this->getSaveCount() - count;
863 for (int i = 0; i < n; ++i) {
864 this->restore();
865 }
866}
867
reed2ff1fce2014-12-11 07:07:37 -0800868void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000869 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700870 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000872
Mike Reedc42a1cd2017-02-14 14:25:14 -0500873 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874}
875
reed4960eee2015-12-18 07:09:18 -0800876bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400877 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000878}
879
reed4960eee2015-12-18 07:09:18 -0800880bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700881 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500882 SkIRect clipBounds = this->getDeviceClipBounds();
883 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000884 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000885 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000886
reed96e657d2015-03-10 17:30:07 -0700887 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
888
Robert Phillips12078432018-05-17 11:17:39 -0400889 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
890 // If the image filter DAG affects transparent black then we will need to render
891 // out to the clip bounds
892 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000893 }
Robert Phillips12078432018-05-17 11:17:39 -0400894
895 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700896 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000897 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700898 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400899 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000900 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400901 inputSaveLayerBounds = clipBounds;
902 }
903
904 if (imageFilter) {
905 // expand the clip bounds by the image filter DAG to include extra content that might
906 // be required by the image filters.
907 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
908 SkImageFilter::kReverse_MapDirection,
909 &inputSaveLayerBounds);
910 }
911
912 SkIRect clippedSaveLayerBounds;
913 if (bounds) {
914 // For better or for worse, user bounds currently act as a hard clip on the layer's
915 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
916 clippedSaveLayerBounds = inputSaveLayerBounds;
917 } else {
918 // If there are no user bounds, we don't want to artificially restrict the resulting
919 // layer bounds, so allow the expanded clip bounds free reign.
920 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000921 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800922
923 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400924 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800925 if (BoundsAffectsClip(saveLayerFlags)) {
926 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
927 fMCRec->fRasterClip.setEmpty();
928 fDeviceClipBounds.setEmpty();
929 }
930 return false;
931 }
Robert Phillips12078432018-05-17 11:17:39 -0400932 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000933
reed4960eee2015-12-18 07:09:18 -0800934 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700935 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400936 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
937 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000938 }
939
940 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400941 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000942 }
Robert Phillips12078432018-05-17 11:17:39 -0400943
junov@chromium.orga907ac32012-02-24 21:54:07 +0000944 return true;
945}
946
reed4960eee2015-12-18 07:09:18 -0800947int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
948 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000949}
950
reed70ee31b2015-12-10 13:44:45 -0800951int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800952 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
953}
954
Cary Clarke041e312018-03-06 13:00:52 -0500955int SkCanvas::saveLayer(const SaveLayerRec& rec) {
956 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
reed4960eee2015-12-18 07:09:18 -0800957 fSaveCount += 1;
Cary Clarke041e312018-03-06 13:00:52 -0500958 this->internalSaveLayer(rec, strategy);
reed4960eee2015-12-18 07:09:18 -0800959 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800960}
961
reeda2217ef2016-07-20 06:04:34 -0700962void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500963 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500964 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700965 SkDraw draw;
966 SkRasterClip rc;
967 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
968 if (!dst->accessPixels(&draw.fDst)) {
969 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800970 }
reeda2217ef2016-07-20 06:04:34 -0700971 draw.fMatrix = &SkMatrix::I();
972 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800973
974 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500975 if (filter) {
976 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
977 }
reeda2217ef2016-07-20 06:04:34 -0700978
Mike Reedc42a1cd2017-02-14 14:25:14 -0500979 int x = src->getOrigin().x() - dstOrigin.x();
980 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700981 auto special = src->snapSpecial();
982 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400983 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700984 }
robertphillips7354a4b2015-12-16 05:08:27 -0800985}
reed70ee31b2015-12-10 13:44:45 -0800986
Mike Kleine083f7c2018-02-07 12:54:27 -0500987static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500988 // Need to force L32 for now if we have an image filter.
989 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
990 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500991 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800992 }
Mike Klein649fb732018-02-26 15:09:16 -0500993
994 SkColorType ct = prev.colorType();
995 if (prev.bytesPerPixel() <= 4) {
996 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
997 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
998 ct = kN32_SkColorType;
999 }
1000 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001001}
1002
reed4960eee2015-12-18 07:09:18 -08001003void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1004 const SkRect* bounds = rec.fBounds;
1005 const SkPaint* paint = rec.fPaint;
1006 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1007
reed8c30a812016-04-20 16:36:51 -07001008 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001009 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001010 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -04001011 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -07001012 SkMatrix remainder;
1013 SkSize scale;
1014 /*
1015 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1016 * but they do handle scaling. To accommodate this, we do the following:
1017 *
1018 * 1. Stash off the current CTM
1019 * 2. Decompose the CTM into SCALE and REMAINDER
1020 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1021 * contains the REMAINDER
1022 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1023 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1024 * of the original imagefilter, and draw that (via drawSprite)
1025 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1026 *
1027 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1028 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1029 */
reed96a04f32016-04-25 09:25:15 -07001030 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001031 stashedMatrix.decomposeScale(&scale, &remainder))
1032 {
1033 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001034 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001035 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1036 SkPaint* p = lazyP.set(*paint);
1037 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1038 SkFilterQuality::kLow_SkFilterQuality,
1039 sk_ref_sp(imageFilter)));
1040 imageFilter = p->getImageFilter();
1041 paint = p;
1042 }
reed8c30a812016-04-20 16:36:51 -07001043
junov@chromium.orga907ac32012-02-24 21:54:07 +00001044 // do this before we create the layer. We don't call the public save() since
1045 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001046 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001047
junov@chromium.orga907ac32012-02-24 21:54:07 +00001048 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001049 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001050 if (modifiedRec) {
1051 // In this case there will be no layer in which to stash the matrix so we need to
1052 // revert the prior MCRec to its earlier state.
1053 modifiedRec->fMatrix = stashedMatrix;
1054 }
reed2ff1fce2014-12-11 07:07:37 -08001055 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056 }
1057
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001058 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1059 // the clipRectBounds() call above?
1060 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001061 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001062 }
1063
reed8dc0ccb2015-03-20 06:32:52 -07001064 SkPixelGeometry geo = fProps.pixelGeometry();
1065 if (paint) {
reed76033be2015-03-14 10:54:31 -07001066 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001067 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001068 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001069 }
1070 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001071
robertphillips5139e502016-07-19 05:10:40 -07001072 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001073 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001074 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001075 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001076 }
reedb2db8982014-11-13 12:41:02 -08001077
Mike Kleine083f7c2018-02-07 12:54:27 -05001078 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001079
Hal Canary704cd322016-11-07 14:13:52 -05001080 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001081 {
reed70ee31b2015-12-10 13:44:45 -08001082 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001083 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001084 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001085 const bool trackCoverage =
1086 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001087 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001088 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001089 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001090 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001091 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1092 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001093 return;
reed61f501f2015-04-29 08:34:00 -07001094 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001095 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001096 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097
Mike Reedb43a3e02017-02-11 10:18:58 -05001098 // only have a "next" if this new layer doesn't affect the clip (rare)
1099 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100 fMCRec->fLayer = layer;
1101 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001102
Mike Reedc61abee2017-02-28 17:45:27 -05001103 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001104 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001105 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001106 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001107
Mike Reedc42a1cd2017-02-14 14:25:14 -05001108 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1109
1110 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1111 if (layer->fNext) {
1112 // need to punch a hole in the previous device, so we don't draw there, given that
1113 // the new top-layer will allow drawing to happen "below" it.
1114 SkRegion hole(ir);
1115 do {
1116 layer = layer->fNext;
1117 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1118 } while (layer->fNext);
1119 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001120}
1121
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001122int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001123 if (0xFF == alpha) {
1124 return this->saveLayer(bounds, nullptr);
1125 } else {
1126 SkPaint tmpPaint;
1127 tmpPaint.setAlpha(alpha);
1128 return this->saveLayer(bounds, &tmpPaint);
1129 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001130}
1131
reed@android.com8a1c16f2008-12-17 15:59:43 +00001132void SkCanvas::internalRestore() {
1133 SkASSERT(fMCStack.count() != 0);
1134
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001135 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001136 DeviceCM* layer = fMCRec->fLayer; // may be null
1137 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001138 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001139
1140 // now do the normal restore()
1141 fMCRec->~MCRec(); // balanced in save()
1142 fMCStack.pop_back();
1143 fMCRec = (MCRec*)fMCStack.back();
1144
Mike Reedc42a1cd2017-02-14 14:25:14 -05001145 if (fMCRec) {
1146 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1147 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001148
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1150 since if we're being recorded, we don't want to record this (the
1151 recorder will have already recorded the restore).
1152 */
bsalomon49f085d2014-09-05 13:34:00 -07001153 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001154 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001155 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001156 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001157 layer->fPaint.get(),
1158 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001159 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001160 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001161 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001162 delete layer;
reedb679ca82015-04-07 04:40:48 -07001163 } else {
1164 // we're at the root
reeda499f902015-05-01 09:34:31 -07001165 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001166 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001167 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001168 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001169 }
msarettfbfa2582016-08-12 08:29:08 -07001170
1171 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001172 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001173 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1174 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001175}
1176
reede8f30622016-03-23 18:59:25 -07001177sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001178 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001179 props = &fProps;
1180 }
1181 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001182}
1183
reede8f30622016-03-23 18:59:25 -07001184sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001185 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001186 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001187}
1188
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001189SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001190 return this->onImageInfo();
1191}
1192
1193SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001194 SkBaseDevice* dev = this->getDevice();
1195 if (dev) {
1196 return dev->imageInfo();
1197 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001198 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001199 }
1200}
1201
brianosman898235c2016-04-06 07:38:23 -07001202bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001203 return this->onGetProps(props);
1204}
1205
1206bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001207 SkBaseDevice* dev = this->getDevice();
1208 if (dev) {
1209 if (props) {
1210 *props = fProps;
1211 }
1212 return true;
1213 } else {
1214 return false;
1215 }
1216}
1217
reed6ceeebd2016-03-09 14:26:26 -08001218bool SkCanvas::peekPixels(SkPixmap* pmap) {
1219 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001220}
1221
reed884e97c2015-05-26 11:31:54 -07001222bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001223 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001224 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001225}
1226
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001227void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001228 SkPixmap pmap;
1229 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001230 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001231 }
1232 if (info) {
1233 *info = pmap.info();
1234 }
1235 if (rowBytes) {
1236 *rowBytes = pmap.rowBytes();
1237 }
1238 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001239 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001240 }
reed884e97c2015-05-26 11:31:54 -07001241 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001242}
1243
reed884e97c2015-05-26 11:31:54 -07001244bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001245 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001246 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001247}
1248
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001250
Florin Malita53f77bd2017-04-28 13:48:37 -04001251void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1252 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001254 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255 paint = &tmp;
1256 }
reed@google.com4b226022011-01-11 18:32:13 +00001257
reed@google.com8926b162012-03-23 15:36:36 +00001258 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001259
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001261 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001262 paint = &looper.paint();
1263 SkImageFilter* filter = paint->getImageFilter();
1264 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001265 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001266 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1267 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001268 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1269 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001270 }
reed@google.com76dd2772012-01-05 21:15:07 +00001271 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001272 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001273 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274 }
reeda2217ef2016-07-20 06:04:34 -07001275
reed@google.com4e2b3d32011-04-07 14:18:59 +00001276 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277}
1278
reed32704672015-12-16 08:27:10 -08001279/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001280
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001281void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001282 if (dx || dy) {
1283 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001284 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001285
reedfe69b502016-09-12 06:31:48 -07001286 // Translate shouldn't affect the is-scale-translateness of the matrix.
1287 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001288
Mike Reedc42a1cd2017-02-14 14:25:14 -05001289 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001290
reedfe69b502016-09-12 06:31:48 -07001291 this->didTranslate(dx,dy);
1292 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293}
1294
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001295void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001296 SkMatrix m;
1297 m.setScale(sx, sy);
1298 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299}
1300
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001301void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001302 SkMatrix m;
1303 m.setRotate(degrees);
1304 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305}
1306
bungeman7438bfc2016-07-12 15:01:19 -07001307void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1308 SkMatrix m;
1309 m.setRotate(degrees, px, py);
1310 this->concat(m);
1311}
1312
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001313void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001314 SkMatrix m;
1315 m.setSkew(sx, sy);
1316 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001317}
1318
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001319void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001320 if (matrix.isIdentity()) {
1321 return;
1322 }
1323
reed2ff1fce2014-12-11 07:07:37 -08001324 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001325 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001326 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001327
Mike Reed7627fa52017-02-08 10:07:53 -05001328 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001329
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001330 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001331}
1332
reed8c30a812016-04-20 16:36:51 -07001333void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001334 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001335 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001336
Mike Reedc42a1cd2017-02-14 14:25:14 -05001337 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001338}
1339
1340void SkCanvas::setMatrix(const SkMatrix& matrix) {
1341 this->checkForDeferredSave();
1342 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001343 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344}
1345
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001347 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001348}
1349
1350//////////////////////////////////////////////////////////////////////////////
1351
Mike Reedc1f77742016-12-09 09:00:50 -05001352void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001353 if (!rect.isFinite()) {
1354 return;
1355 }
reed2ff1fce2014-12-11 07:07:37 -08001356 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001357 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1358 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001359}
1360
Mike Reedc1f77742016-12-09 09:00:50 -05001361void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001362 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001363
Mike Reed7627fa52017-02-08 10:07:53 -05001364 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001365
reedc64eff52015-11-21 12:39:45 -08001366 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001367 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1368 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001369 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001370}
1371
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001372void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1373 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001374 if (fClipRestrictionRect.isEmpty()) {
1375 // we notify the device, but we *dont* resolve deferred saves (since we're just
1376 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001377 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001378 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001379 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001380 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001381 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001382 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001383 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1384 }
1385}
1386
Mike Reedc1f77742016-12-09 09:00:50 -05001387void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001388 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001389 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001390 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001391 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1392 } else {
1393 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001394 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001395}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001396
Mike Reedc1f77742016-12-09 09:00:50 -05001397void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001398 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001399
Brian Salomona3b45d42016-10-03 11:36:16 -04001400 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001401
Mike Reed7627fa52017-02-08 10:07:53 -05001402 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001403
Mike Reed20800c82017-11-15 16:09:04 -05001404 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1405 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001406 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001407}
1408
Mike Reedc1f77742016-12-09 09:00:50 -05001409void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001410 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001411 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001412
1413 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1414 SkRect r;
1415 if (path.isRect(&r)) {
1416 this->onClipRect(r, op, edgeStyle);
1417 return;
1418 }
1419 SkRRect rrect;
1420 if (path.isOval(&r)) {
1421 rrect.setOval(r);
1422 this->onClipRRect(rrect, op, edgeStyle);
1423 return;
1424 }
1425 if (path.isRRect(&rrect)) {
1426 this->onClipRRect(rrect, op, edgeStyle);
1427 return;
1428 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001429 }
robertphillips39f05382015-11-24 09:30:12 -08001430
1431 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001432}
1433
Mike Reedc1f77742016-12-09 09:00:50 -05001434void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001435 AutoValidateClip avc(this);
1436
Brian Salomona3b45d42016-10-03 11:36:16 -04001437 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001438
Mike Reed7627fa52017-02-08 10:07:53 -05001439 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001440
Brian Salomona3b45d42016-10-03 11:36:16 -04001441 const SkPath* rasterClipPath = &path;
1442 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001443 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1444 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001445 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001446}
1447
Mike Reedc1f77742016-12-09 09:00:50 -05001448void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001449 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001450 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001451}
1452
Mike Reedc1f77742016-12-09 09:00:50 -05001453void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001454 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001455
reed@google.com5c3d1472011-02-22 19:12:23 +00001456 AutoValidateClip avc(this);
1457
Mike Reed20800c82017-11-15 16:09:04 -05001458 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001459 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001460}
1461
reed@google.com819c9212011-02-23 18:56:55 +00001462#ifdef SK_DEBUG
1463void SkCanvas::validateClip() const {
1464 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001465 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001466 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001467 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001468 return;
1469 }
reed@google.com819c9212011-02-23 18:56:55 +00001470}
1471#endif
1472
Mike Reeda1361362017-03-07 09:37:29 -05001473bool SkCanvas::androidFramework_isClipAA() const {
1474 bool containsAA = false;
1475
1476 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1477
1478 return containsAA;
1479}
1480
1481class RgnAccumulator {
1482 SkRegion* fRgn;
1483public:
1484 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1485 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1486 SkIPoint origin = device->getOrigin();
1487 if (origin.x() | origin.y()) {
1488 rgn->translate(origin.x(), origin.y());
1489 }
1490 fRgn->op(*rgn, SkRegion::kUnion_Op);
1491 }
1492};
1493
1494void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1495 RgnAccumulator accum(rgn);
1496 SkRegion tmp;
1497
1498 rgn->setEmpty();
1499 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001500}
1501
reed@google.com5c3d1472011-02-22 19:12:23 +00001502///////////////////////////////////////////////////////////////////////////////
1503
reed@google.com754de5f2014-02-24 19:38:20 +00001504bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001505 return fMCRec->fRasterClip.isEmpty();
1506
1507 // TODO: should we only use the conservative answer in a recording canvas?
1508#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001509 SkBaseDevice* dev = this->getTopDevice();
1510 // if no device we return true
1511 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001512#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001513}
1514
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001515bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001516 SkBaseDevice* dev = this->getTopDevice();
1517 // if no device we return false
1518 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001519}
1520
msarettfbfa2582016-08-12 08:29:08 -07001521static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1522#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1523 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1524 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1525 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1526 return 0xF != _mm_movemask_ps(mask);
1527#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1528 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1529 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1530 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1531 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1532#else
1533 SkRect devRectAsRect;
1534 SkRect devClipAsRect;
1535 devRect.store(&devRectAsRect.fLeft);
1536 devClip.store(&devClipAsRect.fLeft);
1537 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1538#endif
1539}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001540
msarettfbfa2582016-08-12 08:29:08 -07001541// It's important for this function to not be inlined. Otherwise the compiler will share code
1542// between the fast path and the slow path, resulting in two slow paths.
1543static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1544 const SkMatrix& matrix) {
1545 SkRect deviceRect;
1546 matrix.mapRect(&deviceRect, src);
1547 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1548}
1549
1550bool SkCanvas::quickReject(const SkRect& src) const {
1551#ifdef SK_DEBUG
1552 // Verify that fDeviceClipBounds are set properly.
1553 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001554 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001555 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001556 } else {
msarettfbfa2582016-08-12 08:29:08 -07001557 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558 }
msarettfbfa2582016-08-12 08:29:08 -07001559
msarett9637ea92016-08-18 14:03:30 -07001560 // Verify that fIsScaleTranslate is set properly.
1561 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001562#endif
1563
msarett9637ea92016-08-18 14:03:30 -07001564 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001565 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1566 }
1567
1568 // We inline the implementation of mapScaleTranslate() for the fast path.
1569 float sx = fMCRec->fMatrix.getScaleX();
1570 float sy = fMCRec->fMatrix.getScaleY();
1571 float tx = fMCRec->fMatrix.getTranslateX();
1572 float ty = fMCRec->fMatrix.getTranslateY();
1573 Sk4f scale(sx, sy, sx, sy);
1574 Sk4f trans(tx, ty, tx, ty);
1575
1576 // Apply matrix.
1577 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1578
1579 // Make sure left < right, top < bottom.
1580 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1581 Sk4f min = Sk4f::Min(ltrb, rblt);
1582 Sk4f max = Sk4f::Max(ltrb, rblt);
1583 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1584 // ARM this sequence generates the fastest (a single instruction).
1585 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1586
1587 // Check if the device rect is NaN or outside the clip.
1588 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001589}
1590
reed@google.com3b3e8952012-08-16 20:53:31 +00001591bool SkCanvas::quickReject(const SkPath& path) const {
1592 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593}
1594
Mike Klein83c8dd92017-11-28 17:08:45 -05001595SkRect SkCanvas::getLocalClipBounds() const {
1596 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001597 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001598 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001599 }
1600
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001601 SkMatrix inverse;
1602 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001603 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001604 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001605 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001606
Mike Reed42e8c532017-01-23 14:09:13 -05001607 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001608 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001609 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001610
Mike Reedb57b9312018-04-23 12:12:54 -04001611 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001612 inverse.mapRect(&bounds, r);
1613 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614}
1615
Mike Klein83c8dd92017-11-28 17:08:45 -05001616SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001617 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001618}
1619
reed@android.com8a1c16f2008-12-17 15:59:43 +00001620const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001621 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001622}
1623
Brian Osman11052242016-10-27 14:47:55 -04001624GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001625 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001626 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001627}
1628
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001629GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001630 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001631 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001632}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001633
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001634void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1635 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001636 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001637 if (outer.isEmpty()) {
1638 return;
1639 }
1640 if (inner.isEmpty()) {
1641 this->drawRRect(outer, paint);
1642 return;
1643 }
1644
1645 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001646 // be able to return ...
1647 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001648 //
1649 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001650 if (!outer.getBounds().contains(inner.getBounds())) {
1651 return;
1652 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001653
1654 this->onDrawDRRect(outer, inner, paint);
1655}
1656
reed41af9662015-01-05 07:49:08 -08001657void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001658 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001659 this->onDrawPaint(paint);
1660}
1661
1662void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001663 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001664 // To avoid redundant logic in our culling code and various backends, we always sort rects
1665 // before passing them along.
1666 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001667}
1668
msarettdca352e2016-08-26 06:37:45 -07001669void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001670 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001671 if (region.isEmpty()) {
1672 return;
1673 }
1674
1675 if (region.isRect()) {
1676 return this->drawIRect(region.getBounds(), paint);
1677 }
1678
1679 this->onDrawRegion(region, paint);
1680}
1681
reed41af9662015-01-05 07:49:08 -08001682void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001683 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001684 // To avoid redundant logic in our culling code and various backends, we always sort rects
1685 // before passing them along.
1686 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001687}
1688
1689void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001690 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001691 this->onDrawRRect(rrect, paint);
1692}
1693
1694void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001695 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001696 this->onDrawPoints(mode, count, pts, paint);
1697}
1698
Mike Reede88a1cb2017-03-17 09:50:46 -04001699void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1700 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001701 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001702 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001703 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1704 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Mike Reede88a1cb2017-03-17 09:50:46 -04001705 this->onDrawVerticesObject(vertices.get(), mode, paint);
1706}
1707
1708void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001709 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001710 RETURN_ON_NULL(vertices);
1711 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001712}
1713
1714void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001715 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001716 this->onDrawPath(path, paint);
1717}
1718
reeda85d4d02015-05-06 12:56:48 -07001719void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001720 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001721 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001722 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001723}
1724
Mike Reedc4e31092018-01-30 11:15:27 -05001725// Returns true if the rect can be "filled" : non-empty and finite
1726static bool fillable(const SkRect& r) {
1727 SkScalar w = r.width();
1728 SkScalar h = r.height();
1729 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1730}
1731
reede47829b2015-08-06 10:02:53 -07001732void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1733 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001734 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001735 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001736 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001737 return;
1738 }
1739 this->onDrawImageRect(image, &src, dst, paint, constraint);
1740}
reed41af9662015-01-05 07:49:08 -08001741
reed84984ef2015-07-17 07:09:43 -07001742void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1743 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001744 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001745 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001746}
1747
reede47829b2015-08-06 10:02:53 -07001748void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1749 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001750 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001751 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1752 constraint);
1753}
reede47829b2015-08-06 10:02:53 -07001754
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001755namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001756class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001757public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001758 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1759 if (!origPaint) {
1760 return;
1761 }
1762 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1763 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1764 }
1765 if (origPaint->getMaskFilter()) {
1766 fPaint.writable()->setMaskFilter(nullptr);
1767 }
1768 if (origPaint->isAntiAlias()) {
1769 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001770 }
1771 }
1772
1773 const SkPaint* get() const {
1774 return fPaint;
1775 }
1776
1777private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001778 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001779};
1780} // namespace
1781
reed4c21dc52015-06-25 12:32:03 -07001782void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1783 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001784 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001785 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001786 if (dst.isEmpty()) {
1787 return;
1788 }
msarett552bca92016-08-03 06:53:26 -07001789 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001790 LatticePaint latticePaint(paint);
1791 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001792 } else {
reede47829b2015-08-06 10:02:53 -07001793 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001794 }
reed4c21dc52015-06-25 12:32:03 -07001795}
1796
msarett16882062016-08-16 09:31:08 -07001797void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1798 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001799 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001800 RETURN_ON_NULL(image);
1801 if (dst.isEmpty()) {
1802 return;
1803 }
msarett71df2d72016-09-30 12:41:42 -07001804
1805 SkIRect bounds;
1806 Lattice latticePlusBounds = lattice;
1807 if (!latticePlusBounds.fBounds) {
1808 bounds = SkIRect::MakeWH(image->width(), image->height());
1809 latticePlusBounds.fBounds = &bounds;
1810 }
1811
1812 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001813 LatticePaint latticePaint(paint);
1814 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001815 } else {
1816 this->drawImageRect(image, dst, paint);
1817 }
1818}
1819
reed41af9662015-01-05 07:49:08 -08001820void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001821 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001822 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001823 return;
1824 }
reed41af9662015-01-05 07:49:08 -08001825 this->onDrawBitmap(bitmap, dx, dy, paint);
1826}
1827
reede47829b2015-08-06 10:02:53 -07001828void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001829 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001830 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001831 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001832 return;
1833 }
reede47829b2015-08-06 10:02:53 -07001834 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001835}
1836
reed84984ef2015-07-17 07:09:43 -07001837void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1838 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001839 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001840}
1841
reede47829b2015-08-06 10:02:53 -07001842void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1843 SrcRectConstraint constraint) {
1844 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1845 constraint);
1846}
reede47829b2015-08-06 10:02:53 -07001847
reed41af9662015-01-05 07:49:08 -08001848void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1849 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001850 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001851 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001852 return;
1853 }
msarett552bca92016-08-03 06:53:26 -07001854 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001855 LatticePaint latticePaint(paint);
1856 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001857 } else {
reeda5517e22015-07-14 10:54:12 -07001858 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001859 }
reed41af9662015-01-05 07:49:08 -08001860}
1861
msarettc573a402016-08-02 08:05:56 -07001862void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1863 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001864 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001865 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001866 return;
1867 }
msarett71df2d72016-09-30 12:41:42 -07001868
1869 SkIRect bounds;
1870 Lattice latticePlusBounds = lattice;
1871 if (!latticePlusBounds.fBounds) {
1872 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1873 latticePlusBounds.fBounds = &bounds;
1874 }
1875
1876 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001877 LatticePaint latticePaint(paint);
1878 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001879 } else {
msarett16882062016-08-16 09:31:08 -07001880 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001881 }
msarettc573a402016-08-02 08:05:56 -07001882}
1883
reed71c3c762015-06-24 10:29:17 -07001884void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001885 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001886 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001887 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001888 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001889 if (count <= 0) {
1890 return;
1891 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001892 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001893 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001894 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001895}
1896
reedf70b5312016-03-04 16:36:20 -08001897void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001898 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001899 if (key) {
1900 this->onDrawAnnotation(rect, key, value);
1901 }
1902}
1903
reede47829b2015-08-06 10:02:53 -07001904void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1905 const SkPaint* paint, SrcRectConstraint constraint) {
1906 if (src) {
1907 this->drawImageRect(image, *src, dst, paint, constraint);
1908 } else {
1909 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1910 dst, paint, constraint);
1911 }
1912}
1913void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1914 const SkPaint* paint, SrcRectConstraint constraint) {
1915 if (src) {
1916 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1917 } else {
1918 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1919 dst, paint, constraint);
1920 }
1921}
1922
Mike Reed4204da22017-05-17 08:53:36 -04001923void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001924 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001925 this->onDrawShadowRec(path, rec);
1926}
1927
1928void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1929 SkPaint paint;
1930 const SkRect& pathBounds = path.getBounds();
1931
1932 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1933 while (iter.next()) {
1934 iter.fDevice->drawShadow(path, rec);
1935 }
1936 LOOPER_END
1937}
1938
reed@android.com8a1c16f2008-12-17 15:59:43 +00001939//////////////////////////////////////////////////////////////////////////////
1940// These are the virtual drawing methods
1941//////////////////////////////////////////////////////////////////////////////
1942
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001943void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001944 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001945 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1946 }
1947}
1948
reed41af9662015-01-05 07:49:08 -08001949void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001950 this->internalDrawPaint(paint);
1951}
1952
1953void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001954 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001955
1956 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001957 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001958 }
1959
reed@google.com4e2b3d32011-04-07 14:18:59 +00001960 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001961}
1962
reed41af9662015-01-05 07:49:08 -08001963void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1964 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001965 if ((long)count <= 0) {
1966 return;
1967 }
1968
Mike Reed822128b2017-02-28 16:41:03 -05001969 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001970 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001971 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001972 // special-case 2 points (common for drawing a single line)
1973 if (2 == count) {
1974 r.set(pts[0], pts[1]);
1975 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001976 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001977 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001978 if (!r.isFinite()) {
1979 return;
1980 }
Mike Reed822128b2017-02-28 16:41:03 -05001981 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001982 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1983 return;
1984 }
1985 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001986 }
reed@google.coma584aed2012-05-16 14:06:02 +00001987
halcanary96fcdcc2015-08-27 07:41:13 -07001988 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001989
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001990 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001991
reed@android.com8a1c16f2008-12-17 15:59:43 +00001992 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001993 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001994 }
reed@google.com4b226022011-01-11 18:32:13 +00001995
reed@google.com4e2b3d32011-04-07 14:18:59 +00001996 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997}
1998
reed4a167172016-08-18 17:15:25 -07001999static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2000 return ((intptr_t)paint.getImageFilter() |
2001#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2002 (intptr_t)canvas->getDrawFilter() |
2003#endif
2004 (intptr_t)paint.getLooper() ) != 0;
2005}
2006
reed41af9662015-01-05 07:49:08 -08002007void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002008 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002009 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002010 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002011 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002012 return;
2013 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002014 }
reed@google.com4b226022011-01-11 18:32:13 +00002015
reed4a167172016-08-18 17:15:25 -07002016 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002017 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018
reed4a167172016-08-18 17:15:25 -07002019 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002020 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002021 }
2022
2023 LOOPER_END
2024 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002025 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002026 SkDrawIter iter(this);
2027 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002028 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002029 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002030 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002031}
2032
msarett44df6512016-08-25 13:54:30 -07002033void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002034 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002035 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002036 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002037 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2038 return;
2039 }
msarett44df6512016-08-25 13:54:30 -07002040 }
2041
Mike Reed822128b2017-02-28 16:41:03 -05002042 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002043
2044 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002045 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002046 }
2047
2048 LOOPER_END
2049}
2050
reed41af9662015-01-05 07:49:08 -08002051void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002052 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002053 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002054 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002055 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002056 return;
2057 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002058 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002059
Mike Reed822128b2017-02-28 16:41:03 -05002060 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002061
2062 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002063 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002064 }
2065
2066 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002067}
2068
bsalomonac3aa242016-08-19 11:25:19 -07002069void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2070 SkScalar sweepAngle, bool useCenter,
2071 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002072 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002073 if (paint.canComputeFastBounds()) {
2074 SkRect storage;
2075 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002076 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002077 return;
2078 }
bsalomonac3aa242016-08-19 11:25:19 -07002079 }
2080
Mike Reed822128b2017-02-28 16:41:03 -05002081 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002082
2083 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002084 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002085 }
2086
2087 LOOPER_END
2088}
2089
reed41af9662015-01-05 07:49:08 -08002090void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002091 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002092 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002093 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2094 return;
2095 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002096 }
2097
2098 if (rrect.isRect()) {
2099 // call the non-virtual version
2100 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002101 return;
2102 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002103 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002104 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2105 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002106 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002107
Mike Reed822128b2017-02-28 16:41:03 -05002108 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002109
2110 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002111 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002112 }
2113
2114 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002115}
2116
Mike Reed822128b2017-02-28 16:41:03 -05002117void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002118 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002119 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002120 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2121 return;
2122 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002123 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002124
Mike Reed822128b2017-02-28 16:41:03 -05002125 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002126
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002127 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002128 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002129 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002130
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002131 LOOPER_END
2132}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002133
reed41af9662015-01-05 07:49:08 -08002134void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002135 if (!path.isFinite()) {
2136 return;
2137 }
2138
Mike Reed822128b2017-02-28 16:41:03 -05002139 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002140 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002141 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002142 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2143 return;
2144 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002146
Mike Reed822128b2017-02-28 16:41:03 -05002147 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002148 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002149 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002150 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002151 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002152 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002153
Mike Reed822128b2017-02-28 16:41:03 -05002154 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002155
2156 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002157 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002158 }
2159
reed@google.com4e2b3d32011-04-07 14:18:59 +00002160 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002161}
2162
reed262a71b2015-12-05 13:07:27 -08002163bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002164 if (!paint.getImageFilter()) {
2165 return false;
2166 }
2167
2168 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002169 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002170 return false;
2171 }
2172
2173 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2174 // Once we can filter and the filter will return a result larger than itself, we should be
2175 // able to remove this constraint.
2176 // skbug.com/4526
2177 //
2178 SkPoint pt;
2179 ctm.mapXY(x, y, &pt);
2180 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2181 return ir.contains(fMCRec->fRasterClip.getBounds());
2182}
2183
Mike Reedf441cfc2018-04-11 14:50:16 -04002184// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2185// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2186// null.
2187static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2188 if (paintParam) {
2189 *real = *paintParam;
2190 real->setStyle(SkPaint::kFill_Style);
2191 real->setPathEffect(nullptr);
2192 paintParam = real;
2193 }
2194 return paintParam;
2195}
2196
reeda85d4d02015-05-06 12:56:48 -07002197void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002198 SkPaint realPaint;
2199 paint = init_image_paint(&realPaint, paint);
2200
reeda85d4d02015-05-06 12:56:48 -07002201 SkRect bounds = SkRect::MakeXYWH(x, y,
2202 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002203 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002204 SkRect tmp = bounds;
2205 if (paint) {
2206 paint->computeFastBounds(tmp, &tmp);
2207 }
2208 if (this->quickReject(tmp)) {
2209 return;
2210 }
reeda85d4d02015-05-06 12:56:48 -07002211 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002212 // At this point we need a real paint object. If the caller passed null, then we should
2213 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2214 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2215 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002216
reeda2217ef2016-07-20 06:04:34 -07002217 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002218 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2219 *paint);
2220 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002221 special = this->getDevice()->makeSpecial(image);
2222 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002223 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002224 }
2225 }
2226
reed262a71b2015-12-05 13:07:27 -08002227 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2228
reeda85d4d02015-05-06 12:56:48 -07002229 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002230 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002231 if (special) {
2232 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002233 iter.fDevice->ctm().mapXY(x, y, &pt);
2234 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002235 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002236 SkScalarRoundToInt(pt.fY), pnt,
2237 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002238 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002239 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002240 }
reeda85d4d02015-05-06 12:56:48 -07002241 }
halcanary9d524f22016-03-29 09:03:52 -07002242
reeda85d4d02015-05-06 12:56:48 -07002243 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002244}
2245
reed41af9662015-01-05 07:49:08 -08002246void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002247 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002248 SkPaint realPaint;
2249 paint = init_image_paint(&realPaint, paint);
2250
halcanary96fcdcc2015-08-27 07:41:13 -07002251 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002252 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002253 if (paint) {
2254 paint->computeFastBounds(dst, &storage);
2255 }
2256 if (this->quickReject(storage)) {
2257 return;
2258 }
reeda85d4d02015-05-06 12:56:48 -07002259 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002260 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002261
senorblancoc41e7e12015-12-07 12:51:30 -08002262 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002263 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002264
reeda85d4d02015-05-06 12:56:48 -07002265 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002266 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002267 }
halcanary9d524f22016-03-29 09:03:52 -07002268
reeda85d4d02015-05-06 12:56:48 -07002269 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002270}
2271
reed41af9662015-01-05 07:49:08 -08002272void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002273 SkDEBUGCODE(bitmap.validate();)
2274
reed33366972015-10-08 09:22:02 -07002275 if (bitmap.drawsNothing()) {
2276 return;
2277 }
2278
Mike Reedf441cfc2018-04-11 14:50:16 -04002279 SkPaint realPaint;
2280 init_image_paint(&realPaint, paint);
2281 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002282
Mike Reed822128b2017-02-28 16:41:03 -05002283 SkRect bounds;
2284 bitmap.getBounds(&bounds);
2285 bounds.offset(x, y);
2286 bool canFastBounds = paint->canComputeFastBounds();
2287 if (canFastBounds) {
2288 SkRect storage;
2289 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002290 return;
2291 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002292 }
reed@google.com4b226022011-01-11 18:32:13 +00002293
reeda2217ef2016-07-20 06:04:34 -07002294 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002295 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2296 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002297 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002298 special = this->getDevice()->makeSpecial(bitmap);
2299 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002300 drawAsSprite = false;
2301 }
2302 }
2303
Mike Reed822128b2017-02-28 16:41:03 -05002304 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002305
2306 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002307 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002308 if (special) {
reed262a71b2015-12-05 13:07:27 -08002309 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002310 iter.fDevice->ctm().mapXY(x, y, &pt);
2311 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002312 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002313 SkScalarRoundToInt(pt.fY), pnt,
2314 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002315 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002316 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002317 }
reed33366972015-10-08 09:22:02 -07002318 }
msarettfbfa2582016-08-12 08:29:08 -07002319
reed33366972015-10-08 09:22:02 -07002320 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002321}
2322
reed@google.com9987ec32011-09-07 11:57:52 +00002323// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002324void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002325 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002326 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002327 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328 return;
2329 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002330
halcanary96fcdcc2015-08-27 07:41:13 -07002331 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002332 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002333 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2334 return;
2335 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002336 }
reed@google.com3d608122011-11-21 15:16:16 +00002337
reed@google.com33535f32012-09-25 15:37:50 +00002338 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002339 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002340 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002341 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002342
senorblancoc41e7e12015-12-07 12:51:30 -08002343 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002344 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002345
reed@google.com33535f32012-09-25 15:37:50 +00002346 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002347 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002348 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002349
reed@google.com33535f32012-09-25 15:37:50 +00002350 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002351}
2352
reed41af9662015-01-05 07:49:08 -08002353void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002354 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002355 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002356 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002357}
2358
reed4c21dc52015-06-25 12:32:03 -07002359void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2360 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002361 SkPaint realPaint;
2362 paint = init_image_paint(&realPaint, paint);
2363
halcanary96fcdcc2015-08-27 07:41:13 -07002364 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002365 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002366 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2367 return;
2368 }
reed@google.com3d608122011-11-21 15:16:16 +00002369 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002370 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002371
senorblancoc41e7e12015-12-07 12:51:30 -08002372 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002373
reed4c21dc52015-06-25 12:32:03 -07002374 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002375 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002376 }
halcanary9d524f22016-03-29 09:03:52 -07002377
reed4c21dc52015-06-25 12:32:03 -07002378 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002379}
2380
reed41af9662015-01-05 07:49:08 -08002381void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2382 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002383 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002384 SkPaint realPaint;
2385 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002386
halcanary96fcdcc2015-08-27 07:41:13 -07002387 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002388 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002389 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2390 return;
2391 }
reed4c21dc52015-06-25 12:32:03 -07002392 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002393 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002394
senorblancoc41e7e12015-12-07 12:51:30 -08002395 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002396
reed4c21dc52015-06-25 12:32:03 -07002397 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002398 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002399 }
halcanary9d524f22016-03-29 09:03:52 -07002400
reed4c21dc52015-06-25 12:32:03 -07002401 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002402}
2403
msarett16882062016-08-16 09:31:08 -07002404void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2405 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002406 SkPaint realPaint;
2407 paint = init_image_paint(&realPaint, paint);
2408
msarett16882062016-08-16 09:31:08 -07002409 if (nullptr == paint || paint->canComputeFastBounds()) {
2410 SkRect storage;
2411 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2412 return;
2413 }
2414 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002415 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002416
2417 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2418
2419 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002420 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002421 }
2422
2423 LOOPER_END
2424}
2425
2426void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2427 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002428 SkPaint realPaint;
2429 paint = init_image_paint(&realPaint, paint);
2430
msarett16882062016-08-16 09:31:08 -07002431 if (nullptr == paint || paint->canComputeFastBounds()) {
2432 SkRect storage;
2433 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2434 return;
2435 }
2436 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002437 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002438
2439 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2440
2441 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002442 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002443 }
2444
2445 LOOPER_END
2446}
2447
reed@google.come0d9ce82014-04-23 04:00:17 +00002448void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2449 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002450
halcanary96fcdcc2015-08-27 07:41:13 -07002451 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002452
2453 while (iter.next()) {
Herb Derby59d997a2018-06-07 12:44:09 -04002454 fScratchGlyphRunBuilder->prepareDrawText(paint, text, byteLength, SkPoint::Make(x, y));
2455 iter.fDevice->drawGlyphRun(looper.paint(), fScratchGlyphRunBuilder.get());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002456 }
2457
reed@google.com4e2b3d32011-04-07 14:18:59 +00002458 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459}
2460
reed@google.come0d9ce82014-04-23 04:00:17 +00002461void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2462 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002463
halcanary96fcdcc2015-08-27 07:41:13 -07002464 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002465
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466 while (iter.next()) {
Herb Derby59d997a2018-06-07 12:44:09 -04002467 fScratchGlyphRunBuilder->prepareDrawPosText(paint, text, byteLength, pos);
2468 iter.fDevice->drawGlyphRun(looper.paint(), fScratchGlyphRunBuilder.get());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002469 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002470
reed@google.com4e2b3d32011-04-07 14:18:59 +00002471 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002472}
2473
reed@google.come0d9ce82014-04-23 04:00:17 +00002474void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2475 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002476
halcanary96fcdcc2015-08-27 07:41:13 -07002477 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002478
reed@android.com8a1c16f2008-12-17 15:59:43 +00002479 while (iter.next()) {
Herb Derby59d997a2018-06-07 12:44:09 -04002480 fScratchGlyphRunBuilder->prepareDrawPosTextH(paint, text, byteLength, xpos, constY);
2481 iter.fDevice->drawGlyphRun(looper.paint(), fScratchGlyphRunBuilder.get());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002483
reed@google.com4e2b3d32011-04-07 14:18:59 +00002484 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002485}
2486
reed@google.come0d9ce82014-04-23 04:00:17 +00002487void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2488 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002489 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002490
reed@android.com8a1c16f2008-12-17 15:59:43 +00002491 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002492 iter.fDevice->drawTextOnPath(text, byteLength, path, matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002493 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002494
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002495 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002496}
2497
reed45561a02016-07-07 12:47:17 -07002498void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2499 const SkRect* cullRect, const SkPaint& paint) {
2500 if (cullRect && this->quickReject(*cullRect)) {
2501 return;
2502 }
2503
2504 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2505
2506 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002507 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002508 }
2509
2510 LOOPER_END
2511}
2512
fmalita00d5c2c2014-08-21 08:53:26 -07002513void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2514 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002515 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002516 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002517 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002518 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002519 SkRect tmp;
2520 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2521 return;
2522 }
2523 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002524 }
2525
fmalita024f9962015-03-03 19:08:17 -08002526 // We cannot filter in the looper as we normally do, because the paint is
2527 // incomplete at this point (text-related attributes are embedded within blob run paints).
2528 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002529 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002530
fmalita85d5eb92015-03-04 11:20:12 -08002531 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002532
fmalitaaa1b9122014-08-28 14:32:24 -07002533 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002534 iter.fDevice->drawTextBlob(blob, x, y, looper.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002535 }
2536
fmalitaaa1b9122014-08-28 14:32:24 -07002537 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002538
2539 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002540}
2541
Cary Clark2a475ea2017-04-28 15:35:12 -04002542void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2543 this->drawText(string.c_str(), string.size(), x, y, paint);
2544}
2545
reed@google.come0d9ce82014-04-23 04:00:17 +00002546// These will become non-virtual, so they always call the (virtual) onDraw... method
2547void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2548 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002549 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002550 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002551 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002552 this->onDrawText(text, byteLength, x, y, paint);
2553 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002554}
2555void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2556 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002557 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002558 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002559 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002560 this->onDrawPosText(text, byteLength, pos, paint);
2561 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002562}
2563void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2564 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002565 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002566 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002567 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002568 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2569 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002570}
2571void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2572 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002573 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002574 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002575 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002576 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2577 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002578}
reed45561a02016-07-07 12:47:17 -07002579void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2580 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002581 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002582 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002583 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002584 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2585 }
2586}
fmalita00d5c2c2014-08-21 08:53:26 -07002587void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2588 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002589 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002590 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002591 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002592 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002593}
reed@google.come0d9ce82014-04-23 04:00:17 +00002594
Mike Reede88a1cb2017-03-17 09:50:46 -04002595void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2596 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002597 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2598
2599 while (iter.next()) {
2600 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002601 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002602 }
2603
2604 LOOPER_END
2605}
2606
dandovb3c9d1c2014-08-12 08:34:29 -07002607void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002608 const SkPoint texCoords[4], SkBlendMode bmode,
2609 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002610 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002611 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002612 return;
2613 }
mtklein6cfa73a2014-08-13 13:33:49 -07002614
Mike Reedfaba3712016-11-03 14:45:31 -04002615 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002616}
2617
2618void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002619 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002620 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002621 // Since a patch is always within the convex hull of the control points, we discard it when its
2622 // bounding rectangle is completely outside the current clip.
2623 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002624 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002625 if (this->quickReject(bounds)) {
2626 return;
2627 }
mtklein6cfa73a2014-08-13 13:33:49 -07002628
Mike Reed435071e2017-05-23 11:22:56 -04002629 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2630
halcanary96fcdcc2015-08-27 07:41:13 -07002631 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002632
dandovecfff212014-08-04 10:02:00 -07002633 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002634 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002635 }
mtklein6cfa73a2014-08-13 13:33:49 -07002636
dandovecfff212014-08-04 10:02:00 -07002637 LOOPER_END
2638}
2639
reeda8db7282015-07-07 10:22:31 -07002640void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002641#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002642 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002643#endif
reede3b38ce2016-01-08 09:18:44 -08002644 RETURN_ON_NULL(dr);
2645 if (x || y) {
2646 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2647 this->onDrawDrawable(dr, &matrix);
2648 } else {
2649 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002650 }
2651}
2652
reeda8db7282015-07-07 10:22:31 -07002653void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002654#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002655 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002656#endif
reede3b38ce2016-01-08 09:18:44 -08002657 RETURN_ON_NULL(dr);
2658 if (matrix && matrix->isIdentity()) {
2659 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002660 }
reede3b38ce2016-01-08 09:18:44 -08002661 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002662}
2663
2664void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002665 // drawable bounds are no longer reliable (e.g. android displaylist)
2666 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002667 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002668}
2669
reed71c3c762015-06-24 10:29:17 -07002670void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002671 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002672 const SkRect* cull, const SkPaint* paint) {
2673 if (cull && this->quickReject(*cull)) {
2674 return;
2675 }
2676
2677 SkPaint pnt;
2678 if (paint) {
2679 pnt = *paint;
2680 }
halcanary9d524f22016-03-29 09:03:52 -07002681
halcanary96fcdcc2015-08-27 07:41:13 -07002682 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002683 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002684 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002685 }
2686 LOOPER_END
2687}
2688
reedf70b5312016-03-04 16:36:20 -08002689void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2690 SkASSERT(key);
2691
2692 SkPaint paint;
2693 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2694 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002695 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002696 }
2697 LOOPER_END
2698}
2699
reed@android.com8a1c16f2008-12-17 15:59:43 +00002700//////////////////////////////////////////////////////////////////////////////
2701// These methods are NOT virtual, and therefore must call back into virtual
2702// methods, rather than actually drawing themselves.
2703//////////////////////////////////////////////////////////////////////////////
2704
reed374772b2016-10-05 17:33:02 -07002705void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002706 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002707 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002708 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002709 this->drawPaint(paint);
2710}
2711
2712void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002713 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2715}
2716
Mike Reed3661bc92017-02-22 13:21:42 -05002717void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002718 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002719 pts[0].set(x0, y0);
2720 pts[1].set(x1, y1);
2721 this->drawPoints(kLines_PointMode, 2, pts, paint);
2722}
2723
Mike Reed3661bc92017-02-22 13:21:42 -05002724void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002725 if (radius < 0) {
2726 radius = 0;
2727 }
2728
2729 SkRect r;
2730 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002731 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002732}
2733
2734void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2735 const SkPaint& paint) {
2736 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002737 SkRRect rrect;
2738 rrect.setRectXY(r, rx, ry);
2739 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740 } else {
2741 this->drawRect(r, paint);
2742 }
2743}
2744
reed@android.com8a1c16f2008-12-17 15:59:43 +00002745void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2746 SkScalar sweepAngle, bool useCenter,
2747 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002748 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002749 if (oval.isEmpty() || !sweepAngle) {
2750 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 }
bsalomon21af9ca2016-08-25 12:29:23 -07002752 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753}
2754
2755void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2756 const SkPath& path, SkScalar hOffset,
2757 SkScalar vOffset, const SkPaint& paint) {
2758 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002759
reed@android.com8a1c16f2008-12-17 15:59:43 +00002760 matrix.setTranslate(hOffset, vOffset);
2761 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2762}
2763
reed@android.comf76bacf2009-05-13 14:00:33 +00002764///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002765
Mike Klein88d90712018-01-27 17:30:04 +00002766/**
2767 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2768 * against the playback cost of recursing into the subpicture to get at its actual ops.
2769 *
2770 * For now we pick a conservatively small value, though measurement (and other heuristics like
2771 * the type of ops contained) may justify changing this value.
2772 */
2773#define kMaxPictureOpsToUnrollInsteadOfRef 1
2774
reedd5fa1a42014-08-09 11:08:05 -07002775void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002776 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002777 RETURN_ON_NULL(picture);
2778
reede3b38ce2016-01-08 09:18:44 -08002779 if (matrix && matrix->isIdentity()) {
2780 matrix = nullptr;
2781 }
Mike Klein88d90712018-01-27 17:30:04 +00002782 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2783 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2784 picture->playback(this);
2785 } else {
2786 this->onDrawPicture(picture, matrix, paint);
2787 }
reedd5fa1a42014-08-09 11:08:05 -07002788}
robertphillips9b14f262014-06-04 05:40:44 -07002789
reedd5fa1a42014-08-09 11:08:05 -07002790void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2791 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002792 if (!paint || paint->canComputeFastBounds()) {
2793 SkRect bounds = picture->cullRect();
2794 if (paint) {
2795 paint->computeFastBounds(bounds, &bounds);
2796 }
2797 if (matrix) {
2798 matrix->mapRect(&bounds);
2799 }
2800 if (this->quickReject(bounds)) {
2801 return;
2802 }
2803 }
2804
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002805 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002806 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807}
2808
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809///////////////////////////////////////////////////////////////////////////////
2810///////////////////////////////////////////////////////////////////////////////
2811
reed3aafe112016-08-18 12:45:34 -07002812SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002813 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814
2815 SkASSERT(canvas);
2816
reed3aafe112016-08-18 12:45:34 -07002817 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002818 fDone = !fImpl->next();
2819}
2820
2821SkCanvas::LayerIter::~LayerIter() {
2822 fImpl->~SkDrawIter();
2823}
2824
2825void SkCanvas::LayerIter::next() {
2826 fDone = !fImpl->next();
2827}
2828
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002829SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002830 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831}
2832
2833const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002834 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002835}
2836
2837const SkPaint& SkCanvas::LayerIter::paint() const {
2838 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002839 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840 paint = &fDefaultPaint;
2841 }
2842 return *paint;
2843}
2844
Mike Reedca37f322018-03-08 13:22:16 -05002845SkIRect SkCanvas::LayerIter::clipBounds() const {
2846 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002847}
2848
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2850int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002851
2852///////////////////////////////////////////////////////////////////////////////
2853
Brian Osman10fc6fd2018-03-02 11:01:10 -05002854// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002855static bool supported_for_raster_canvas(const SkImageInfo& info) {
2856 switch (info.alphaType()) {
2857 case kPremul_SkAlphaType:
2858 case kOpaque_SkAlphaType:
2859 break;
2860 default:
2861 return false;
2862 }
2863
2864 switch (info.colorType()) {
2865 case kAlpha_8_SkColorType:
2866 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002867 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002868 case kRGBA_F16_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002869 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002870 break;
2871 default:
2872 return false;
2873 }
2874
2875 return true;
2876}
2877
Mike Reed5df49342016-11-12 08:06:55 -06002878std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002879 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002880 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002881 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002882 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002883
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002884 SkBitmap bitmap;
2885 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002886 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002887 }
Mike Reed12f77342017-11-08 11:19:52 -05002888
2889 return props ?
2890 skstd::make_unique<SkCanvas>(bitmap, *props) :
2891 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002892}
reedd5fa1a42014-08-09 11:08:05 -07002893
2894///////////////////////////////////////////////////////////////////////////////
2895
Florin Malitaee424ac2016-12-01 12:47:59 -05002896SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2897 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2898
Florin Malita439ace92016-12-02 12:05:41 -05002899SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2900 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2901
Herb Derbyefe39bc2018-05-01 17:06:20 -04002902SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002903 : INHERITED(device) {}
2904
Florin Malitaee424ac2016-12-01 12:47:59 -05002905SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2906 (void)this->INHERITED::getSaveLayerStrategy(rec);
2907 return kNoLayer_SaveLayerStrategy;
2908}
2909
2910///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002911
reed73603f32016-09-20 08:42:38 -07002912static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2913static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2914static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2915static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2916static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2917static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002918
2919///////////////////////////////////////////////////////////////////////////////////////////////////
2920
2921SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2922 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002923 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002924 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2925 SkIPoint origin = dev->getOrigin();
2926 SkMatrix ctm = this->getTotalMatrix();
2927 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2928
2929 SkIRect clip = fMCRec->fRasterClip.getBounds();
2930 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002931 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002932 clip.setEmpty();
2933 }
2934
2935 fAllocator->updateHandle(handle, ctm, clip);
2936 return handle;
2937 }
2938 return nullptr;
2939}
2940
2941static bool install(SkBitmap* bm, const SkImageInfo& info,
2942 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002943 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002944}
2945
2946SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2947 SkBitmap* bm) {
2948 SkRasterHandleAllocator::Rec rec;
2949 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2950 return nullptr;
2951 }
2952 return rec.fHandle;
2953}
2954
2955std::unique_ptr<SkCanvas>
2956SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2957 const SkImageInfo& info, const Rec* rec) {
2958 if (!alloc || !supported_for_raster_canvas(info)) {
2959 return nullptr;
2960 }
2961
2962 SkBitmap bm;
2963 Handle hndl;
2964
2965 if (rec) {
2966 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2967 } else {
2968 hndl = alloc->allocBitmap(info, &bm);
2969 }
2970 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2971}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002972
2973///////////////////////////////////////////////////////////////////////////////////////////////////
2974
2975