blob: bf32aafae9e29484765ab4058e6b424efc38cb24 [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);
Ruiqi Maof5101492018-06-29 14:32:21 -04001705 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001706}
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);
Ruiqi Maof5101492018-06-29 14:32:21 -04001711 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1712}
1713
1714void SkCanvas::drawVertices(const sk_sp<SkVertices> vertices, const SkMatrix* bones, int boneCount,
1715 SkBlendMode mode, const SkPaint& paint) {
1716 TRACE_EVENT0("skia", TRACE_FUNC);
1717 RETURN_ON_NULL(vertices);
1718 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1719}
1720
1721void SkCanvas::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
1722 SkBlendMode mode, const SkPaint& paint) {
1723 TRACE_EVENT0("skia", TRACE_FUNC);
1724 RETURN_ON_NULL(vertices);
1725 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001726}
1727
1728void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001729 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001730 this->onDrawPath(path, paint);
1731}
1732
reeda85d4d02015-05-06 12:56:48 -07001733void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001734 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001735 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001736 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001737}
1738
Mike Reedc4e31092018-01-30 11:15:27 -05001739// Returns true if the rect can be "filled" : non-empty and finite
1740static bool fillable(const SkRect& r) {
1741 SkScalar w = r.width();
1742 SkScalar h = r.height();
1743 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1744}
1745
reede47829b2015-08-06 10:02:53 -07001746void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1747 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001748 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001749 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001750 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001751 return;
1752 }
1753 this->onDrawImageRect(image, &src, dst, paint, constraint);
1754}
reed41af9662015-01-05 07:49:08 -08001755
reed84984ef2015-07-17 07:09:43 -07001756void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1757 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001758 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001759 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001760}
1761
reede47829b2015-08-06 10:02:53 -07001762void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1763 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001764 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001765 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1766 constraint);
1767}
reede47829b2015-08-06 10:02:53 -07001768
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001769namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001770class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001771public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001772 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1773 if (!origPaint) {
1774 return;
1775 }
1776 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1777 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1778 }
1779 if (origPaint->getMaskFilter()) {
1780 fPaint.writable()->setMaskFilter(nullptr);
1781 }
1782 if (origPaint->isAntiAlias()) {
1783 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001784 }
1785 }
1786
1787 const SkPaint* get() const {
1788 return fPaint;
1789 }
1790
1791private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001792 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001793};
1794} // namespace
1795
reed4c21dc52015-06-25 12:32:03 -07001796void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1797 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001798 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001799 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001800 if (dst.isEmpty()) {
1801 return;
1802 }
msarett552bca92016-08-03 06:53:26 -07001803 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001804 LatticePaint latticePaint(paint);
1805 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001806 } else {
reede47829b2015-08-06 10:02:53 -07001807 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001808 }
reed4c21dc52015-06-25 12:32:03 -07001809}
1810
msarett16882062016-08-16 09:31:08 -07001811void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1812 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001813 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001814 RETURN_ON_NULL(image);
1815 if (dst.isEmpty()) {
1816 return;
1817 }
msarett71df2d72016-09-30 12:41:42 -07001818
1819 SkIRect bounds;
1820 Lattice latticePlusBounds = lattice;
1821 if (!latticePlusBounds.fBounds) {
1822 bounds = SkIRect::MakeWH(image->width(), image->height());
1823 latticePlusBounds.fBounds = &bounds;
1824 }
1825
1826 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001827 LatticePaint latticePaint(paint);
1828 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001829 } else {
1830 this->drawImageRect(image, dst, paint);
1831 }
1832}
1833
reed41af9662015-01-05 07:49:08 -08001834void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001835 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001836 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001837 return;
1838 }
reed41af9662015-01-05 07:49:08 -08001839 this->onDrawBitmap(bitmap, dx, dy, paint);
1840}
1841
reede47829b2015-08-06 10:02:53 -07001842void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001843 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001844 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001845 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001846 return;
1847 }
reede47829b2015-08-06 10:02:53 -07001848 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001849}
1850
reed84984ef2015-07-17 07:09:43 -07001851void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1852 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001853 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001854}
1855
reede47829b2015-08-06 10:02:53 -07001856void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1857 SrcRectConstraint constraint) {
1858 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1859 constraint);
1860}
reede47829b2015-08-06 10:02:53 -07001861
reed41af9662015-01-05 07:49:08 -08001862void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1863 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001864 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001865 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001866 return;
1867 }
msarett552bca92016-08-03 06:53:26 -07001868 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001869 LatticePaint latticePaint(paint);
1870 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001871 } else {
reeda5517e22015-07-14 10:54:12 -07001872 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001873 }
reed41af9662015-01-05 07:49:08 -08001874}
1875
msarettc573a402016-08-02 08:05:56 -07001876void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1877 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001878 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001879 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001880 return;
1881 }
msarett71df2d72016-09-30 12:41:42 -07001882
1883 SkIRect bounds;
1884 Lattice latticePlusBounds = lattice;
1885 if (!latticePlusBounds.fBounds) {
1886 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1887 latticePlusBounds.fBounds = &bounds;
1888 }
1889
1890 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001891 LatticePaint latticePaint(paint);
1892 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001893 } else {
msarett16882062016-08-16 09:31:08 -07001894 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001895 }
msarettc573a402016-08-02 08:05:56 -07001896}
1897
reed71c3c762015-06-24 10:29:17 -07001898void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001899 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001900 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001901 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001902 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001903 if (count <= 0) {
1904 return;
1905 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001906 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001907 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001908 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001909}
1910
reedf70b5312016-03-04 16:36:20 -08001911void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001912 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001913 if (key) {
1914 this->onDrawAnnotation(rect, key, value);
1915 }
1916}
1917
reede47829b2015-08-06 10:02:53 -07001918void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1919 const SkPaint* paint, SrcRectConstraint constraint) {
1920 if (src) {
1921 this->drawImageRect(image, *src, dst, paint, constraint);
1922 } else {
1923 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1924 dst, paint, constraint);
1925 }
1926}
1927void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1928 const SkPaint* paint, SrcRectConstraint constraint) {
1929 if (src) {
1930 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1931 } else {
1932 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1933 dst, paint, constraint);
1934 }
1935}
1936
Mike Reed4204da22017-05-17 08:53:36 -04001937void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001938 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001939 this->onDrawShadowRec(path, rec);
1940}
1941
1942void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1943 SkPaint paint;
1944 const SkRect& pathBounds = path.getBounds();
1945
1946 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1947 while (iter.next()) {
1948 iter.fDevice->drawShadow(path, rec);
1949 }
1950 LOOPER_END
1951}
1952
reed@android.com8a1c16f2008-12-17 15:59:43 +00001953//////////////////////////////////////////////////////////////////////////////
1954// These are the virtual drawing methods
1955//////////////////////////////////////////////////////////////////////////////
1956
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001957void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001958 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001959 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1960 }
1961}
1962
reed41af9662015-01-05 07:49:08 -08001963void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001964 this->internalDrawPaint(paint);
1965}
1966
1967void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001968 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001969
1970 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001971 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001972 }
1973
reed@google.com4e2b3d32011-04-07 14:18:59 +00001974 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001975}
1976
reed41af9662015-01-05 07:49:08 -08001977void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1978 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001979 if ((long)count <= 0) {
1980 return;
1981 }
1982
Mike Reed822128b2017-02-28 16:41:03 -05001983 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001984 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001985 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001986 // special-case 2 points (common for drawing a single line)
1987 if (2 == count) {
1988 r.set(pts[0], pts[1]);
1989 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001990 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001991 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001992 if (!r.isFinite()) {
1993 return;
1994 }
Mike Reed822128b2017-02-28 16:41:03 -05001995 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001996 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1997 return;
1998 }
1999 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002000 }
reed@google.coma584aed2012-05-16 14:06:02 +00002001
halcanary96fcdcc2015-08-27 07:41:13 -07002002 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002003
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002004 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002005
reed@android.com8a1c16f2008-12-17 15:59:43 +00002006 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002007 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002008 }
reed@google.com4b226022011-01-11 18:32:13 +00002009
reed@google.com4e2b3d32011-04-07 14:18:59 +00002010 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002011}
2012
reed4a167172016-08-18 17:15:25 -07002013static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2014 return ((intptr_t)paint.getImageFilter() |
2015#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2016 (intptr_t)canvas->getDrawFilter() |
2017#endif
2018 (intptr_t)paint.getLooper() ) != 0;
2019}
2020
reed41af9662015-01-05 07:49:08 -08002021void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002022 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002023 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002024 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002025 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002026 return;
2027 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002028 }
reed@google.com4b226022011-01-11 18:32:13 +00002029
reed4a167172016-08-18 17:15:25 -07002030 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002031 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002032
reed4a167172016-08-18 17:15:25 -07002033 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002034 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002035 }
2036
2037 LOOPER_END
2038 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002039 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002040 SkDrawIter iter(this);
2041 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002042 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002043 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002044 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002045}
2046
msarett44df6512016-08-25 13:54:30 -07002047void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002048 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002049 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002050 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002051 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2052 return;
2053 }
msarett44df6512016-08-25 13:54:30 -07002054 }
2055
Mike Reed822128b2017-02-28 16:41:03 -05002056 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002057
2058 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002059 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002060 }
2061
2062 LOOPER_END
2063}
2064
reed41af9662015-01-05 07:49:08 -08002065void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002066 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002067 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002068 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002069 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002070 return;
2071 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002072 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002073
Mike Reed822128b2017-02-28 16:41:03 -05002074 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002075
2076 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002077 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002078 }
2079
2080 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002081}
2082
bsalomonac3aa242016-08-19 11:25:19 -07002083void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2084 SkScalar sweepAngle, bool useCenter,
2085 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002086 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002087 if (paint.canComputeFastBounds()) {
2088 SkRect storage;
2089 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002090 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002091 return;
2092 }
bsalomonac3aa242016-08-19 11:25:19 -07002093 }
2094
Mike Reed822128b2017-02-28 16:41:03 -05002095 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002096
2097 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002098 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002099 }
2100
2101 LOOPER_END
2102}
2103
reed41af9662015-01-05 07:49:08 -08002104void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002105 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002106 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002107 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2108 return;
2109 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002110 }
2111
2112 if (rrect.isRect()) {
2113 // call the non-virtual version
2114 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002115 return;
2116 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002117 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002118 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2119 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002120 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002121
Mike Reed822128b2017-02-28 16:41:03 -05002122 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002123
2124 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002125 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002126 }
2127
2128 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002129}
2130
Mike Reed822128b2017-02-28 16:41:03 -05002131void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002132 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002133 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002134 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2135 return;
2136 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002137 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002138
Mike Reed822128b2017-02-28 16:41:03 -05002139 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002140
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002141 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002142 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002143 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002144
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002145 LOOPER_END
2146}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002147
reed41af9662015-01-05 07:49:08 -08002148void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002149 if (!path.isFinite()) {
2150 return;
2151 }
2152
Mike Reed822128b2017-02-28 16:41:03 -05002153 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002154 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002155 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002156 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2157 return;
2158 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002159 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002160
Mike Reed822128b2017-02-28 16:41:03 -05002161 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002162 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002163 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002164 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002165 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002166 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002167
Mike Reed822128b2017-02-28 16:41:03 -05002168 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002169
2170 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002171 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002172 }
2173
reed@google.com4e2b3d32011-04-07 14:18:59 +00002174 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002175}
2176
reed262a71b2015-12-05 13:07:27 -08002177bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002178 if (!paint.getImageFilter()) {
2179 return false;
2180 }
2181
2182 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002183 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002184 return false;
2185 }
2186
2187 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2188 // Once we can filter and the filter will return a result larger than itself, we should be
2189 // able to remove this constraint.
2190 // skbug.com/4526
2191 //
2192 SkPoint pt;
2193 ctm.mapXY(x, y, &pt);
2194 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2195 return ir.contains(fMCRec->fRasterClip.getBounds());
2196}
2197
Mike Reedf441cfc2018-04-11 14:50:16 -04002198// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2199// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2200// null.
2201static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2202 if (paintParam) {
2203 *real = *paintParam;
2204 real->setStyle(SkPaint::kFill_Style);
2205 real->setPathEffect(nullptr);
2206 paintParam = real;
2207 }
2208 return paintParam;
2209}
2210
reeda85d4d02015-05-06 12:56:48 -07002211void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002212 SkPaint realPaint;
2213 paint = init_image_paint(&realPaint, paint);
2214
reeda85d4d02015-05-06 12:56:48 -07002215 SkRect bounds = SkRect::MakeXYWH(x, y,
2216 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002217 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002218 SkRect tmp = bounds;
2219 if (paint) {
2220 paint->computeFastBounds(tmp, &tmp);
2221 }
2222 if (this->quickReject(tmp)) {
2223 return;
2224 }
reeda85d4d02015-05-06 12:56:48 -07002225 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002226 // At this point we need a real paint object. If the caller passed null, then we should
2227 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2228 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2229 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002230
reeda2217ef2016-07-20 06:04:34 -07002231 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002232 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2233 *paint);
2234 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002235 special = this->getDevice()->makeSpecial(image);
2236 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002237 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002238 }
2239 }
2240
reed262a71b2015-12-05 13:07:27 -08002241 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2242
reeda85d4d02015-05-06 12:56:48 -07002243 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002244 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002245 if (special) {
2246 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002247 iter.fDevice->ctm().mapXY(x, y, &pt);
2248 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002249 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002250 SkScalarRoundToInt(pt.fY), pnt,
2251 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002252 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002253 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002254 }
reeda85d4d02015-05-06 12:56:48 -07002255 }
halcanary9d524f22016-03-29 09:03:52 -07002256
reeda85d4d02015-05-06 12:56:48 -07002257 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002258}
2259
reed41af9662015-01-05 07:49:08 -08002260void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002261 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002262 SkPaint realPaint;
2263 paint = init_image_paint(&realPaint, paint);
2264
halcanary96fcdcc2015-08-27 07:41:13 -07002265 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002266 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002267 if (paint) {
2268 paint->computeFastBounds(dst, &storage);
2269 }
2270 if (this->quickReject(storage)) {
2271 return;
2272 }
reeda85d4d02015-05-06 12:56:48 -07002273 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002274 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002275
senorblancoc41e7e12015-12-07 12:51:30 -08002276 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002277 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002278
reeda85d4d02015-05-06 12:56:48 -07002279 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002280 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002281 }
halcanary9d524f22016-03-29 09:03:52 -07002282
reeda85d4d02015-05-06 12:56:48 -07002283 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002284}
2285
reed41af9662015-01-05 07:49:08 -08002286void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002287 SkDEBUGCODE(bitmap.validate();)
2288
reed33366972015-10-08 09:22:02 -07002289 if (bitmap.drawsNothing()) {
2290 return;
2291 }
2292
Mike Reedf441cfc2018-04-11 14:50:16 -04002293 SkPaint realPaint;
2294 init_image_paint(&realPaint, paint);
2295 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002296
Mike Reed822128b2017-02-28 16:41:03 -05002297 SkRect bounds;
2298 bitmap.getBounds(&bounds);
2299 bounds.offset(x, y);
2300 bool canFastBounds = paint->canComputeFastBounds();
2301 if (canFastBounds) {
2302 SkRect storage;
2303 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002304 return;
2305 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002306 }
reed@google.com4b226022011-01-11 18:32:13 +00002307
reeda2217ef2016-07-20 06:04:34 -07002308 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002309 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2310 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002311 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002312 special = this->getDevice()->makeSpecial(bitmap);
2313 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002314 drawAsSprite = false;
2315 }
2316 }
2317
Mike Reed822128b2017-02-28 16:41:03 -05002318 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002319
2320 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002321 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002322 if (special) {
reed262a71b2015-12-05 13:07:27 -08002323 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002324 iter.fDevice->ctm().mapXY(x, y, &pt);
2325 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002326 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002327 SkScalarRoundToInt(pt.fY), pnt,
2328 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002329 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002330 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002331 }
reed33366972015-10-08 09:22:02 -07002332 }
msarettfbfa2582016-08-12 08:29:08 -07002333
reed33366972015-10-08 09:22:02 -07002334 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002335}
2336
reed@google.com9987ec32011-09-07 11:57:52 +00002337// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002338void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002339 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002340 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002341 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002342 return;
2343 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002344
halcanary96fcdcc2015-08-27 07:41:13 -07002345 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002346 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002347 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2348 return;
2349 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002350 }
reed@google.com3d608122011-11-21 15:16:16 +00002351
reed@google.com33535f32012-09-25 15:37:50 +00002352 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002353 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002354 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002355 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002356
senorblancoc41e7e12015-12-07 12:51:30 -08002357 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002358 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002359
reed@google.com33535f32012-09-25 15:37:50 +00002360 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002361 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002362 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002363
reed@google.com33535f32012-09-25 15:37:50 +00002364 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002365}
2366
reed41af9662015-01-05 07:49:08 -08002367void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002368 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002369 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002370 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002371}
2372
reed4c21dc52015-06-25 12:32:03 -07002373void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2374 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002375 SkPaint realPaint;
2376 paint = init_image_paint(&realPaint, paint);
2377
halcanary96fcdcc2015-08-27 07:41:13 -07002378 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002379 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002380 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2381 return;
2382 }
reed@google.com3d608122011-11-21 15:16:16 +00002383 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002384 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002385
senorblancoc41e7e12015-12-07 12:51:30 -08002386 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002387
reed4c21dc52015-06-25 12:32:03 -07002388 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002389 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002390 }
halcanary9d524f22016-03-29 09:03:52 -07002391
reed4c21dc52015-06-25 12:32:03 -07002392 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002393}
2394
reed41af9662015-01-05 07:49:08 -08002395void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2396 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002397 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002398 SkPaint realPaint;
2399 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002400
halcanary96fcdcc2015-08-27 07:41:13 -07002401 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002402 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002403 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2404 return;
2405 }
reed4c21dc52015-06-25 12:32:03 -07002406 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002407 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002408
senorblancoc41e7e12015-12-07 12:51:30 -08002409 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002410
reed4c21dc52015-06-25 12:32:03 -07002411 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002412 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002413 }
halcanary9d524f22016-03-29 09:03:52 -07002414
reed4c21dc52015-06-25 12:32:03 -07002415 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002416}
2417
msarett16882062016-08-16 09:31:08 -07002418void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2419 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002420 SkPaint realPaint;
2421 paint = init_image_paint(&realPaint, paint);
2422
msarett16882062016-08-16 09:31:08 -07002423 if (nullptr == paint || paint->canComputeFastBounds()) {
2424 SkRect storage;
2425 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2426 return;
2427 }
2428 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002429 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002430
2431 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2432
2433 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002434 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002435 }
2436
2437 LOOPER_END
2438}
2439
2440void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2441 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002442 SkPaint realPaint;
2443 paint = init_image_paint(&realPaint, paint);
2444
msarett16882062016-08-16 09:31:08 -07002445 if (nullptr == paint || paint->canComputeFastBounds()) {
2446 SkRect storage;
2447 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2448 return;
2449 }
2450 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002451 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002452
2453 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2454
2455 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002456 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002457 }
2458
2459 LOOPER_END
2460}
2461
reed@google.come0d9ce82014-04-23 04:00:17 +00002462void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2463 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002464
halcanary96fcdcc2015-08-27 07:41:13 -07002465 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466
2467 while (iter.next()) {
Herb Derby4a447432018-06-22 11:45:27 -04002468 fScratchGlyphRunBuilder->prepareDrawText(
2469 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Robert Phillips38580452018-06-28 12:00:35 +00002470 auto glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
2471 iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002472 }
2473
reed@google.com4e2b3d32011-04-07 14:18:59 +00002474 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002475}
2476
reed@google.come0d9ce82014-04-23 04:00:17 +00002477void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2478 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002479
halcanary96fcdcc2015-08-27 07:41:13 -07002480 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002481
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 while (iter.next()) {
Herb Derby4a447432018-06-22 11:45:27 -04002483 fScratchGlyphRunBuilder->prepareDrawPosText(looper.paint(), text, byteLength, pos);
Robert Phillips38580452018-06-28 12:00:35 +00002484 auto glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
2485 iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002486 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002487
reed@google.com4e2b3d32011-04-07 14:18:59 +00002488 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002489}
2490
reed@google.come0d9ce82014-04-23 04:00:17 +00002491void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2492 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002493
halcanary96fcdcc2015-08-27 07:41:13 -07002494 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002495
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496 while (iter.next()) {
Herb Derby4a447432018-06-22 11:45:27 -04002497 fScratchGlyphRunBuilder->prepareDrawPosTextH(
2498 looper.paint(), text, byteLength, xpos, constY);
Robert Phillips38580452018-06-28 12:00:35 +00002499 const auto& glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
2500 iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002501 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002502
reed@google.com4e2b3d32011-04-07 14:18:59 +00002503 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002504}
2505
reed@google.come0d9ce82014-04-23 04:00:17 +00002506void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2507 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002508 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002509
reed@android.com8a1c16f2008-12-17 15:59:43 +00002510 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002511 iter.fDevice->drawTextOnPath(text, byteLength, path, matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002512 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002513
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002514 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002515}
2516
reed45561a02016-07-07 12:47:17 -07002517void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2518 const SkRect* cullRect, const SkPaint& paint) {
2519 if (cullRect && this->quickReject(*cullRect)) {
2520 return;
2521 }
2522
2523 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2524
2525 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002526 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002527 }
2528
2529 LOOPER_END
2530}
2531
fmalita00d5c2c2014-08-21 08:53:26 -07002532void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2533 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002534 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002535 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002536 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002537 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002538 SkRect tmp;
2539 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2540 return;
2541 }
2542 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002543 }
2544
fmalita024f9962015-03-03 19:08:17 -08002545 // We cannot filter in the looper as we normally do, because the paint is
2546 // incomplete at this point (text-related attributes are embedded within blob run paints).
2547 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002548 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002549
fmalita85d5eb92015-03-04 11:20:12 -08002550 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002551
fmalitaaa1b9122014-08-28 14:32:24 -07002552 while (iter.next()) {
Robert Phillips38580452018-06-28 12:00:35 +00002553 iter.fDevice->drawTextBlob(blob, x, y, looper.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002554 }
2555
fmalitaaa1b9122014-08-28 14:32:24 -07002556 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002557
2558 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002559}
2560
Cary Clark2a475ea2017-04-28 15:35:12 -04002561void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2562 this->drawText(string.c_str(), string.size(), x, y, paint);
2563}
2564
reed@google.come0d9ce82014-04-23 04:00:17 +00002565// These will become non-virtual, so they always call the (virtual) onDraw... method
2566void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2567 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002568 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002569 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002570 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002571 this->onDrawText(text, byteLength, x, y, paint);
2572 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002573}
2574void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2575 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002576 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002577 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002578 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002579 this->onDrawPosText(text, byteLength, pos, paint);
2580 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002581}
2582void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2583 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002584 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002585 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002586 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002587 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2588 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002589}
2590void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2591 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002592 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002593 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002594 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002595 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2596 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002597}
reed45561a02016-07-07 12:47:17 -07002598void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2599 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002600 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002601 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002602 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002603 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2604 }
2605}
fmalita00d5c2c2014-08-21 08:53:26 -07002606void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2607 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002608 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002609 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002610 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002611 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002612}
reed@google.come0d9ce82014-04-23 04:00:17 +00002613
Ruiqi Maof5101492018-06-29 14:32:21 -04002614void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
2615 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002616 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2617
2618 while (iter.next()) {
2619 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002620 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002621 }
2622
2623 LOOPER_END
2624}
2625
dandovb3c9d1c2014-08-12 08:34:29 -07002626void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002627 const SkPoint texCoords[4], SkBlendMode bmode,
2628 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002629 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002630 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002631 return;
2632 }
mtklein6cfa73a2014-08-13 13:33:49 -07002633
Mike Reedfaba3712016-11-03 14:45:31 -04002634 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002635}
2636
2637void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002638 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002639 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002640 // Since a patch is always within the convex hull of the control points, we discard it when its
2641 // bounding rectangle is completely outside the current clip.
2642 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002643 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002644 if (this->quickReject(bounds)) {
2645 return;
2646 }
mtklein6cfa73a2014-08-13 13:33:49 -07002647
Mike Reed435071e2017-05-23 11:22:56 -04002648 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2649
halcanary96fcdcc2015-08-27 07:41:13 -07002650 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002651
dandovecfff212014-08-04 10:02:00 -07002652 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002653 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002654 }
mtklein6cfa73a2014-08-13 13:33:49 -07002655
dandovecfff212014-08-04 10:02:00 -07002656 LOOPER_END
2657}
2658
reeda8db7282015-07-07 10:22:31 -07002659void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002660#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002661 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002662#endif
reede3b38ce2016-01-08 09:18:44 -08002663 RETURN_ON_NULL(dr);
2664 if (x || y) {
2665 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2666 this->onDrawDrawable(dr, &matrix);
2667 } else {
2668 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002669 }
2670}
2671
reeda8db7282015-07-07 10:22:31 -07002672void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002673#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002674 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002675#endif
reede3b38ce2016-01-08 09:18:44 -08002676 RETURN_ON_NULL(dr);
2677 if (matrix && matrix->isIdentity()) {
2678 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002679 }
reede3b38ce2016-01-08 09:18:44 -08002680 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002681}
2682
2683void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002684 // drawable bounds are no longer reliable (e.g. android displaylist)
2685 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002686 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002687}
2688
reed71c3c762015-06-24 10:29:17 -07002689void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002690 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002691 const SkRect* cull, const SkPaint* paint) {
2692 if (cull && this->quickReject(*cull)) {
2693 return;
2694 }
2695
2696 SkPaint pnt;
2697 if (paint) {
2698 pnt = *paint;
2699 }
halcanary9d524f22016-03-29 09:03:52 -07002700
halcanary96fcdcc2015-08-27 07:41:13 -07002701 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002702 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002703 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002704 }
2705 LOOPER_END
2706}
2707
reedf70b5312016-03-04 16:36:20 -08002708void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2709 SkASSERT(key);
2710
2711 SkPaint paint;
2712 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2713 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002714 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002715 }
2716 LOOPER_END
2717}
2718
reed@android.com8a1c16f2008-12-17 15:59:43 +00002719//////////////////////////////////////////////////////////////////////////////
2720// These methods are NOT virtual, and therefore must call back into virtual
2721// methods, rather than actually drawing themselves.
2722//////////////////////////////////////////////////////////////////////////////
2723
reed374772b2016-10-05 17:33:02 -07002724void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002725 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002727 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728 this->drawPaint(paint);
2729}
2730
2731void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002732 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002733 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2734}
2735
Mike Reed3661bc92017-02-22 13:21:42 -05002736void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002737 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002738 pts[0].set(x0, y0);
2739 pts[1].set(x1, y1);
2740 this->drawPoints(kLines_PointMode, 2, pts, paint);
2741}
2742
Mike Reed3661bc92017-02-22 13:21:42 -05002743void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002744 if (radius < 0) {
2745 radius = 0;
2746 }
2747
2748 SkRect r;
2749 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002750 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751}
2752
2753void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2754 const SkPaint& paint) {
2755 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002756 SkRRect rrect;
2757 rrect.setRectXY(r, rx, ry);
2758 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002759 } else {
2760 this->drawRect(r, paint);
2761 }
2762}
2763
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2765 SkScalar sweepAngle, bool useCenter,
2766 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002767 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002768 if (oval.isEmpty() || !sweepAngle) {
2769 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 }
bsalomon21af9ca2016-08-25 12:29:23 -07002771 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772}
2773
2774void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2775 const SkPath& path, SkScalar hOffset,
2776 SkScalar vOffset, const SkPaint& paint) {
2777 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002778
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779 matrix.setTranslate(hOffset, vOffset);
2780 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2781}
2782
reed@android.comf76bacf2009-05-13 14:00:33 +00002783///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002784
Mike Klein88d90712018-01-27 17:30:04 +00002785/**
2786 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2787 * against the playback cost of recursing into the subpicture to get at its actual ops.
2788 *
2789 * For now we pick a conservatively small value, though measurement (and other heuristics like
2790 * the type of ops contained) may justify changing this value.
2791 */
2792#define kMaxPictureOpsToUnrollInsteadOfRef 1
2793
reedd5fa1a42014-08-09 11:08:05 -07002794void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002795 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002796 RETURN_ON_NULL(picture);
2797
reede3b38ce2016-01-08 09:18:44 -08002798 if (matrix && matrix->isIdentity()) {
2799 matrix = nullptr;
2800 }
Mike Klein88d90712018-01-27 17:30:04 +00002801 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2802 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2803 picture->playback(this);
2804 } else {
2805 this->onDrawPicture(picture, matrix, paint);
2806 }
reedd5fa1a42014-08-09 11:08:05 -07002807}
robertphillips9b14f262014-06-04 05:40:44 -07002808
reedd5fa1a42014-08-09 11:08:05 -07002809void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2810 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002811 if (!paint || paint->canComputeFastBounds()) {
2812 SkRect bounds = picture->cullRect();
2813 if (paint) {
2814 paint->computeFastBounds(bounds, &bounds);
2815 }
2816 if (matrix) {
2817 matrix->mapRect(&bounds);
2818 }
2819 if (this->quickReject(bounds)) {
2820 return;
2821 }
2822 }
2823
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002824 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002825 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826}
2827
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828///////////////////////////////////////////////////////////////////////////////
2829///////////////////////////////////////////////////////////////////////////////
2830
reed3aafe112016-08-18 12:45:34 -07002831SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002832 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833
2834 SkASSERT(canvas);
2835
reed3aafe112016-08-18 12:45:34 -07002836 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837 fDone = !fImpl->next();
2838}
2839
2840SkCanvas::LayerIter::~LayerIter() {
2841 fImpl->~SkDrawIter();
2842}
2843
2844void SkCanvas::LayerIter::next() {
2845 fDone = !fImpl->next();
2846}
2847
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002848SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002849 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002850}
2851
2852const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002853 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002854}
2855
2856const SkPaint& SkCanvas::LayerIter::paint() const {
2857 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002858 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002859 paint = &fDefaultPaint;
2860 }
2861 return *paint;
2862}
2863
Mike Reedca37f322018-03-08 13:22:16 -05002864SkIRect SkCanvas::LayerIter::clipBounds() const {
2865 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002866}
2867
reed@android.com8a1c16f2008-12-17 15:59:43 +00002868int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2869int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002870
2871///////////////////////////////////////////////////////////////////////////////
2872
Brian Osman10fc6fd2018-03-02 11:01:10 -05002873// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002874static bool supported_for_raster_canvas(const SkImageInfo& info) {
2875 switch (info.alphaType()) {
2876 case kPremul_SkAlphaType:
2877 case kOpaque_SkAlphaType:
2878 break;
2879 default:
2880 return false;
2881 }
2882
2883 switch (info.colorType()) {
2884 case kAlpha_8_SkColorType:
2885 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002886 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002887 case kRGBA_F16_SkColorType:
Mike Klein37854712018-06-26 11:43:06 -04002888 case kRGBA_F32_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002889 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002890 break;
2891 default:
2892 return false;
2893 }
2894
2895 return true;
2896}
2897
Mike Reed5df49342016-11-12 08:06:55 -06002898std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002899 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002900 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002901 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002902 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002903
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002904 SkBitmap bitmap;
2905 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002906 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002907 }
Mike Reed12f77342017-11-08 11:19:52 -05002908
2909 return props ?
2910 skstd::make_unique<SkCanvas>(bitmap, *props) :
2911 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002912}
reedd5fa1a42014-08-09 11:08:05 -07002913
2914///////////////////////////////////////////////////////////////////////////////
2915
Florin Malitaee424ac2016-12-01 12:47:59 -05002916SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2917 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2918
Florin Malita439ace92016-12-02 12:05:41 -05002919SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2920 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2921
Herb Derbyefe39bc2018-05-01 17:06:20 -04002922SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002923 : INHERITED(device) {}
2924
Florin Malitaee424ac2016-12-01 12:47:59 -05002925SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2926 (void)this->INHERITED::getSaveLayerStrategy(rec);
2927 return kNoLayer_SaveLayerStrategy;
2928}
2929
2930///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002931
reed73603f32016-09-20 08:42:38 -07002932static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2933static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2934static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2935static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2936static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2937static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002938
2939///////////////////////////////////////////////////////////////////////////////////////////////////
2940
2941SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2942 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002943 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002944 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2945 SkIPoint origin = dev->getOrigin();
2946 SkMatrix ctm = this->getTotalMatrix();
2947 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2948
2949 SkIRect clip = fMCRec->fRasterClip.getBounds();
2950 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002951 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002952 clip.setEmpty();
2953 }
2954
2955 fAllocator->updateHandle(handle, ctm, clip);
2956 return handle;
2957 }
2958 return nullptr;
2959}
2960
2961static bool install(SkBitmap* bm, const SkImageInfo& info,
2962 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002963 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002964}
2965
2966SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2967 SkBitmap* bm) {
2968 SkRasterHandleAllocator::Rec rec;
2969 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2970 return nullptr;
2971 }
2972 return rec.fHandle;
2973}
2974
2975std::unique_ptr<SkCanvas>
2976SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2977 const SkImageInfo& info, const Rec* rec) {
2978 if (!alloc || !supported_for_raster_canvas(info)) {
2979 return nullptr;
2980 }
2981
2982 SkBitmap bm;
2983 Handle hndl;
2984
2985 if (rec) {
2986 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2987 } else {
2988 hndl = alloc->allocBitmap(info, &bm);
2989 }
2990 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2991}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002992
2993///////////////////////////////////////////////////////////////////////////////////////////////////
2994
2995