blob: 5b2a2cf3c28fe451748d3d6cb9a42e0f8d99fe75 [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
Ruiqi Mao94d57c42018-07-02 15:20:10 -04001714void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkMatrix* bones, int boneCount,
Ruiqi Maof5101492018-06-29 14:32:21 -04001715 SkBlendMode mode, const SkPaint& paint) {
1716 TRACE_EVENT0("skia", TRACE_FUNC);
1717 RETURN_ON_NULL(vertices);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -04001718 SkASSERT(boneCount <= 100);
Ruiqi Maof5101492018-06-29 14:32:21 -04001719 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1720}
1721
1722void SkCanvas::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
1723 SkBlendMode mode, const SkPaint& paint) {
1724 TRACE_EVENT0("skia", TRACE_FUNC);
1725 RETURN_ON_NULL(vertices);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -04001726 SkASSERT(boneCount <= 100);
Ruiqi Maof5101492018-06-29 14:32:21 -04001727 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001728}
1729
1730void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001731 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001732 this->onDrawPath(path, paint);
1733}
1734
reeda85d4d02015-05-06 12:56:48 -07001735void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001736 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001737 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001738 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001739}
1740
Mike Reedc4e31092018-01-30 11:15:27 -05001741// Returns true if the rect can be "filled" : non-empty and finite
1742static bool fillable(const SkRect& r) {
1743 SkScalar w = r.width();
1744 SkScalar h = r.height();
1745 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1746}
1747
reede47829b2015-08-06 10:02:53 -07001748void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1749 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001750 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001751 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001752 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001753 return;
1754 }
1755 this->onDrawImageRect(image, &src, dst, paint, constraint);
1756}
reed41af9662015-01-05 07:49:08 -08001757
reed84984ef2015-07-17 07:09:43 -07001758void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1759 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001760 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001761 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001762}
1763
reede47829b2015-08-06 10:02:53 -07001764void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1765 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001766 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001767 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1768 constraint);
1769}
reede47829b2015-08-06 10:02:53 -07001770
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001771namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001772class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001773public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001774 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1775 if (!origPaint) {
1776 return;
1777 }
1778 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1779 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1780 }
1781 if (origPaint->getMaskFilter()) {
1782 fPaint.writable()->setMaskFilter(nullptr);
1783 }
1784 if (origPaint->isAntiAlias()) {
1785 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001786 }
1787 }
1788
1789 const SkPaint* get() const {
1790 return fPaint;
1791 }
1792
1793private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001794 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001795};
1796} // namespace
1797
reed4c21dc52015-06-25 12:32:03 -07001798void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1799 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001800 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001801 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001802 if (dst.isEmpty()) {
1803 return;
1804 }
msarett552bca92016-08-03 06:53:26 -07001805 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001806 LatticePaint latticePaint(paint);
1807 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001808 } else {
reede47829b2015-08-06 10:02:53 -07001809 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001810 }
reed4c21dc52015-06-25 12:32:03 -07001811}
1812
msarett16882062016-08-16 09:31:08 -07001813void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1814 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001815 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001816 RETURN_ON_NULL(image);
1817 if (dst.isEmpty()) {
1818 return;
1819 }
msarett71df2d72016-09-30 12:41:42 -07001820
1821 SkIRect bounds;
1822 Lattice latticePlusBounds = lattice;
1823 if (!latticePlusBounds.fBounds) {
1824 bounds = SkIRect::MakeWH(image->width(), image->height());
1825 latticePlusBounds.fBounds = &bounds;
1826 }
1827
1828 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001829 LatticePaint latticePaint(paint);
1830 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001831 } else {
1832 this->drawImageRect(image, dst, paint);
1833 }
1834}
1835
reed41af9662015-01-05 07:49:08 -08001836void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001837 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001838 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001839 return;
1840 }
reed41af9662015-01-05 07:49:08 -08001841 this->onDrawBitmap(bitmap, dx, dy, paint);
1842}
1843
reede47829b2015-08-06 10:02:53 -07001844void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001845 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001846 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001847 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001848 return;
1849 }
reede47829b2015-08-06 10:02:53 -07001850 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001851}
1852
reed84984ef2015-07-17 07:09:43 -07001853void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1854 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001855 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001856}
1857
reede47829b2015-08-06 10:02:53 -07001858void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1859 SrcRectConstraint constraint) {
1860 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1861 constraint);
1862}
reede47829b2015-08-06 10:02:53 -07001863
reed41af9662015-01-05 07:49:08 -08001864void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1865 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001866 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001867 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001868 return;
1869 }
msarett552bca92016-08-03 06:53:26 -07001870 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001871 LatticePaint latticePaint(paint);
1872 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001873 } else {
reeda5517e22015-07-14 10:54:12 -07001874 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001875 }
reed41af9662015-01-05 07:49:08 -08001876}
1877
msarettc573a402016-08-02 08:05:56 -07001878void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1879 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001880 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001881 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001882 return;
1883 }
msarett71df2d72016-09-30 12:41:42 -07001884
1885 SkIRect bounds;
1886 Lattice latticePlusBounds = lattice;
1887 if (!latticePlusBounds.fBounds) {
1888 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1889 latticePlusBounds.fBounds = &bounds;
1890 }
1891
1892 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001893 LatticePaint latticePaint(paint);
1894 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001895 } else {
msarett16882062016-08-16 09:31:08 -07001896 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001897 }
msarettc573a402016-08-02 08:05:56 -07001898}
1899
reed71c3c762015-06-24 10:29:17 -07001900void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001901 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001902 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001903 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001904 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001905 if (count <= 0) {
1906 return;
1907 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001908 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001909 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001910 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001911}
1912
reedf70b5312016-03-04 16:36:20 -08001913void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001914 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001915 if (key) {
1916 this->onDrawAnnotation(rect, key, value);
1917 }
1918}
1919
reede47829b2015-08-06 10:02:53 -07001920void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1921 const SkPaint* paint, SrcRectConstraint constraint) {
1922 if (src) {
1923 this->drawImageRect(image, *src, dst, paint, constraint);
1924 } else {
1925 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1926 dst, paint, constraint);
1927 }
1928}
1929void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1930 const SkPaint* paint, SrcRectConstraint constraint) {
1931 if (src) {
1932 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1933 } else {
1934 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1935 dst, paint, constraint);
1936 }
1937}
1938
Mike Reed4204da22017-05-17 08:53:36 -04001939void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001940 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001941 this->onDrawShadowRec(path, rec);
1942}
1943
1944void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1945 SkPaint paint;
1946 const SkRect& pathBounds = path.getBounds();
1947
1948 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1949 while (iter.next()) {
1950 iter.fDevice->drawShadow(path, rec);
1951 }
1952 LOOPER_END
1953}
1954
reed@android.com8a1c16f2008-12-17 15:59:43 +00001955//////////////////////////////////////////////////////////////////////////////
1956// These are the virtual drawing methods
1957//////////////////////////////////////////////////////////////////////////////
1958
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001959void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001960 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001961 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1962 }
1963}
1964
reed41af9662015-01-05 07:49:08 -08001965void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001966 this->internalDrawPaint(paint);
1967}
1968
1969void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001970 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001971
1972 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001973 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001974 }
1975
reed@google.com4e2b3d32011-04-07 14:18:59 +00001976 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001977}
1978
reed41af9662015-01-05 07:49:08 -08001979void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1980 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001981 if ((long)count <= 0) {
1982 return;
1983 }
1984
Mike Reed822128b2017-02-28 16:41:03 -05001985 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001986 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001987 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001988 // special-case 2 points (common for drawing a single line)
1989 if (2 == count) {
1990 r.set(pts[0], pts[1]);
1991 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001992 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001993 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001994 if (!r.isFinite()) {
1995 return;
1996 }
Mike Reed822128b2017-02-28 16:41:03 -05001997 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001998 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1999 return;
2000 }
2001 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002002 }
reed@google.coma584aed2012-05-16 14:06:02 +00002003
halcanary96fcdcc2015-08-27 07:41:13 -07002004 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002005
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002006 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002007
reed@android.com8a1c16f2008-12-17 15:59:43 +00002008 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002009 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002010 }
reed@google.com4b226022011-01-11 18:32:13 +00002011
reed@google.com4e2b3d32011-04-07 14:18:59 +00002012 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002013}
2014
reed4a167172016-08-18 17:15:25 -07002015static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2016 return ((intptr_t)paint.getImageFilter() |
2017#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2018 (intptr_t)canvas->getDrawFilter() |
2019#endif
2020 (intptr_t)paint.getLooper() ) != 0;
2021}
2022
reed41af9662015-01-05 07:49:08 -08002023void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002024 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002025 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002026 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002027 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002028 return;
2029 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002030 }
reed@google.com4b226022011-01-11 18:32:13 +00002031
reed4a167172016-08-18 17:15:25 -07002032 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002033 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002034
reed4a167172016-08-18 17:15:25 -07002035 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002036 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002037 }
2038
2039 LOOPER_END
2040 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002041 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002042 SkDrawIter iter(this);
2043 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002044 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002045 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002046 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002047}
2048
msarett44df6512016-08-25 13:54:30 -07002049void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002050 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002051 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002052 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002053 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2054 return;
2055 }
msarett44df6512016-08-25 13:54:30 -07002056 }
2057
Mike Reed822128b2017-02-28 16:41:03 -05002058 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002059
2060 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002061 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002062 }
2063
2064 LOOPER_END
2065}
2066
reed41af9662015-01-05 07:49:08 -08002067void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002068 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002069 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002070 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002071 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002072 return;
2073 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002074 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002075
Mike Reed822128b2017-02-28 16:41:03 -05002076 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002077
2078 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002079 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002080 }
2081
2082 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002083}
2084
bsalomonac3aa242016-08-19 11:25:19 -07002085void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2086 SkScalar sweepAngle, bool useCenter,
2087 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002088 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002089 if (paint.canComputeFastBounds()) {
2090 SkRect storage;
2091 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002092 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002093 return;
2094 }
bsalomonac3aa242016-08-19 11:25:19 -07002095 }
2096
Mike Reed822128b2017-02-28 16:41:03 -05002097 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002098
2099 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002100 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002101 }
2102
2103 LOOPER_END
2104}
2105
reed41af9662015-01-05 07:49:08 -08002106void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002107 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002108 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002109 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2110 return;
2111 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002112 }
2113
2114 if (rrect.isRect()) {
2115 // call the non-virtual version
2116 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002117 return;
2118 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002119 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002120 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2121 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002122 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002123
Mike Reed822128b2017-02-28 16:41:03 -05002124 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002125
2126 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002127 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002128 }
2129
2130 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002131}
2132
Mike Reed822128b2017-02-28 16:41:03 -05002133void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002134 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002135 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002136 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2137 return;
2138 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002139 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002140
Mike Reed822128b2017-02-28 16:41:03 -05002141 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002142
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002143 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002144 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002145 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002146
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002147 LOOPER_END
2148}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002149
reed41af9662015-01-05 07:49:08 -08002150void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002151 if (!path.isFinite()) {
2152 return;
2153 }
2154
Mike Reed822128b2017-02-28 16:41:03 -05002155 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002156 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002157 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002158 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2159 return;
2160 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002161 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002162
Mike Reed822128b2017-02-28 16:41:03 -05002163 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002164 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002165 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002166 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002167 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002168 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002169
Mike Reed822128b2017-02-28 16:41:03 -05002170 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002171
2172 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002173 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002174 }
2175
reed@google.com4e2b3d32011-04-07 14:18:59 +00002176 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002177}
2178
reed262a71b2015-12-05 13:07:27 -08002179bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002180 if (!paint.getImageFilter()) {
2181 return false;
2182 }
2183
2184 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002185 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002186 return false;
2187 }
2188
2189 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2190 // Once we can filter and the filter will return a result larger than itself, we should be
2191 // able to remove this constraint.
2192 // skbug.com/4526
2193 //
2194 SkPoint pt;
2195 ctm.mapXY(x, y, &pt);
2196 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2197 return ir.contains(fMCRec->fRasterClip.getBounds());
2198}
2199
Mike Reedf441cfc2018-04-11 14:50:16 -04002200// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2201// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2202// null.
2203static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2204 if (paintParam) {
2205 *real = *paintParam;
2206 real->setStyle(SkPaint::kFill_Style);
2207 real->setPathEffect(nullptr);
2208 paintParam = real;
2209 }
2210 return paintParam;
2211}
2212
reeda85d4d02015-05-06 12:56:48 -07002213void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002214 SkPaint realPaint;
2215 paint = init_image_paint(&realPaint, paint);
2216
reeda85d4d02015-05-06 12:56:48 -07002217 SkRect bounds = SkRect::MakeXYWH(x, y,
2218 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002219 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002220 SkRect tmp = bounds;
2221 if (paint) {
2222 paint->computeFastBounds(tmp, &tmp);
2223 }
2224 if (this->quickReject(tmp)) {
2225 return;
2226 }
reeda85d4d02015-05-06 12:56:48 -07002227 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002228 // At this point we need a real paint object. If the caller passed null, then we should
2229 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2230 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2231 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002232
reeda2217ef2016-07-20 06:04:34 -07002233 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002234 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2235 *paint);
2236 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002237 special = this->getDevice()->makeSpecial(image);
2238 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002239 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002240 }
2241 }
2242
reed262a71b2015-12-05 13:07:27 -08002243 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2244
reeda85d4d02015-05-06 12:56:48 -07002245 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002246 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002247 if (special) {
2248 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002249 iter.fDevice->ctm().mapXY(x, y, &pt);
2250 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002251 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002252 SkScalarRoundToInt(pt.fY), pnt,
2253 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002254 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002255 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002256 }
reeda85d4d02015-05-06 12:56:48 -07002257 }
halcanary9d524f22016-03-29 09:03:52 -07002258
reeda85d4d02015-05-06 12:56:48 -07002259 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002260}
2261
reed41af9662015-01-05 07:49:08 -08002262void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002263 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002264 SkPaint realPaint;
2265 paint = init_image_paint(&realPaint, paint);
2266
halcanary96fcdcc2015-08-27 07:41:13 -07002267 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002268 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002269 if (paint) {
2270 paint->computeFastBounds(dst, &storage);
2271 }
2272 if (this->quickReject(storage)) {
2273 return;
2274 }
reeda85d4d02015-05-06 12:56:48 -07002275 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002276 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002277
senorblancoc41e7e12015-12-07 12:51:30 -08002278 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002279 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002280
reeda85d4d02015-05-06 12:56:48 -07002281 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002282 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002283 }
halcanary9d524f22016-03-29 09:03:52 -07002284
reeda85d4d02015-05-06 12:56:48 -07002285 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002286}
2287
reed41af9662015-01-05 07:49:08 -08002288void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002289 SkDEBUGCODE(bitmap.validate();)
2290
reed33366972015-10-08 09:22:02 -07002291 if (bitmap.drawsNothing()) {
2292 return;
2293 }
2294
Mike Reedf441cfc2018-04-11 14:50:16 -04002295 SkPaint realPaint;
2296 init_image_paint(&realPaint, paint);
2297 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002298
Mike Reed822128b2017-02-28 16:41:03 -05002299 SkRect bounds;
2300 bitmap.getBounds(&bounds);
2301 bounds.offset(x, y);
2302 bool canFastBounds = paint->canComputeFastBounds();
2303 if (canFastBounds) {
2304 SkRect storage;
2305 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002306 return;
2307 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308 }
reed@google.com4b226022011-01-11 18:32:13 +00002309
reeda2217ef2016-07-20 06:04:34 -07002310 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002311 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2312 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002313 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002314 special = this->getDevice()->makeSpecial(bitmap);
2315 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002316 drawAsSprite = false;
2317 }
2318 }
2319
Mike Reed822128b2017-02-28 16:41:03 -05002320 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002321
2322 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002323 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002324 if (special) {
reed262a71b2015-12-05 13:07:27 -08002325 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002326 iter.fDevice->ctm().mapXY(x, y, &pt);
2327 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002328 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002329 SkScalarRoundToInt(pt.fY), pnt,
2330 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002331 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002332 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002333 }
reed33366972015-10-08 09:22:02 -07002334 }
msarettfbfa2582016-08-12 08:29:08 -07002335
reed33366972015-10-08 09:22:02 -07002336 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002337}
2338
reed@google.com9987ec32011-09-07 11:57:52 +00002339// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002340void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002341 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002342 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002343 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002344 return;
2345 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002346
halcanary96fcdcc2015-08-27 07:41:13 -07002347 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002348 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002349 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2350 return;
2351 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352 }
reed@google.com3d608122011-11-21 15:16:16 +00002353
reed@google.com33535f32012-09-25 15:37:50 +00002354 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002355 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002356 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002357 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002358
senorblancoc41e7e12015-12-07 12:51:30 -08002359 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002360 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002361
reed@google.com33535f32012-09-25 15:37:50 +00002362 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002363 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002364 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002365
reed@google.com33535f32012-09-25 15:37:50 +00002366 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002367}
2368
reed41af9662015-01-05 07:49:08 -08002369void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002370 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002371 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002372 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002373}
2374
reed4c21dc52015-06-25 12:32:03 -07002375void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2376 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002377 SkPaint realPaint;
2378 paint = init_image_paint(&realPaint, paint);
2379
halcanary96fcdcc2015-08-27 07:41:13 -07002380 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002381 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002382 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2383 return;
2384 }
reed@google.com3d608122011-11-21 15:16:16 +00002385 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002386 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002387
senorblancoc41e7e12015-12-07 12:51:30 -08002388 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002389
reed4c21dc52015-06-25 12:32:03 -07002390 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002391 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002392 }
halcanary9d524f22016-03-29 09:03:52 -07002393
reed4c21dc52015-06-25 12:32:03 -07002394 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002395}
2396
reed41af9662015-01-05 07:49:08 -08002397void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2398 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002399 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002400 SkPaint realPaint;
2401 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002402
halcanary96fcdcc2015-08-27 07:41:13 -07002403 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002404 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002405 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2406 return;
2407 }
reed4c21dc52015-06-25 12:32:03 -07002408 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002409 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002410
senorblancoc41e7e12015-12-07 12:51:30 -08002411 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002412
reed4c21dc52015-06-25 12:32:03 -07002413 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002414 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002415 }
halcanary9d524f22016-03-29 09:03:52 -07002416
reed4c21dc52015-06-25 12:32:03 -07002417 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002418}
2419
msarett16882062016-08-16 09:31:08 -07002420void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2421 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002422 SkPaint realPaint;
2423 paint = init_image_paint(&realPaint, paint);
2424
msarett16882062016-08-16 09:31:08 -07002425 if (nullptr == paint || paint->canComputeFastBounds()) {
2426 SkRect storage;
2427 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2428 return;
2429 }
2430 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002431 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002432
2433 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2434
2435 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002436 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002437 }
2438
2439 LOOPER_END
2440}
2441
2442void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2443 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002444 SkPaint realPaint;
2445 paint = init_image_paint(&realPaint, paint);
2446
msarett16882062016-08-16 09:31:08 -07002447 if (nullptr == paint || paint->canComputeFastBounds()) {
2448 SkRect storage;
2449 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2450 return;
2451 }
2452 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002453 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002454
2455 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2456
2457 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002458 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002459 }
2460
2461 LOOPER_END
2462}
2463
reed@google.come0d9ce82014-04-23 04:00:17 +00002464void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2465 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002466
halcanary96fcdcc2015-08-27 07:41:13 -07002467 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002468
2469 while (iter.next()) {
Herb Derby4a447432018-06-22 11:45:27 -04002470 fScratchGlyphRunBuilder->prepareDrawText(
2471 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Robert Phillips38580452018-06-28 12:00:35 +00002472 auto glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
2473 iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474 }
2475
reed@google.com4e2b3d32011-04-07 14:18:59 +00002476 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002477}
2478
reed@google.come0d9ce82014-04-23 04:00:17 +00002479void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2480 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002481
halcanary96fcdcc2015-08-27 07:41:13 -07002482 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002483
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484 while (iter.next()) {
Herb Derby4a447432018-06-22 11:45:27 -04002485 fScratchGlyphRunBuilder->prepareDrawPosText(looper.paint(), text, byteLength, pos);
Robert Phillips38580452018-06-28 12:00:35 +00002486 auto glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
2487 iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002489
reed@google.com4e2b3d32011-04-07 14:18:59 +00002490 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002491}
2492
reed@google.come0d9ce82014-04-23 04:00:17 +00002493void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2494 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002495
halcanary96fcdcc2015-08-27 07:41:13 -07002496 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002497
reed@android.com8a1c16f2008-12-17 15:59:43 +00002498 while (iter.next()) {
Herb Derby4a447432018-06-22 11:45:27 -04002499 fScratchGlyphRunBuilder->prepareDrawPosTextH(
2500 looper.paint(), text, byteLength, xpos, constY);
Robert Phillips38580452018-06-28 12:00:35 +00002501 const auto& glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
2502 iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002504
reed@google.com4e2b3d32011-04-07 14:18:59 +00002505 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002506}
2507
reed@google.come0d9ce82014-04-23 04:00:17 +00002508void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2509 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002510 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002511
reed@android.com8a1c16f2008-12-17 15:59:43 +00002512 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002513 iter.fDevice->drawTextOnPath(text, byteLength, path, matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002514 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002515
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002516 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002517}
2518
reed45561a02016-07-07 12:47:17 -07002519void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2520 const SkRect* cullRect, const SkPaint& paint) {
2521 if (cullRect && this->quickReject(*cullRect)) {
2522 return;
2523 }
2524
2525 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2526
2527 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002528 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002529 }
2530
2531 LOOPER_END
2532}
2533
fmalita00d5c2c2014-08-21 08:53:26 -07002534void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2535 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002536 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002537 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002538 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002539 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002540 SkRect tmp;
2541 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2542 return;
2543 }
2544 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002545 }
2546
fmalita024f9962015-03-03 19:08:17 -08002547 // We cannot filter in the looper as we normally do, because the paint is
2548 // incomplete at this point (text-related attributes are embedded within blob run paints).
2549 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002550 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002551
fmalita85d5eb92015-03-04 11:20:12 -08002552 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002553
fmalitaaa1b9122014-08-28 14:32:24 -07002554 while (iter.next()) {
Robert Phillips38580452018-06-28 12:00:35 +00002555 iter.fDevice->drawTextBlob(blob, x, y, looper.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002556 }
2557
fmalitaaa1b9122014-08-28 14:32:24 -07002558 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002559
2560 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002561}
2562
Cary Clark2a475ea2017-04-28 15:35:12 -04002563void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2564 this->drawText(string.c_str(), string.size(), x, y, paint);
2565}
2566
reed@google.come0d9ce82014-04-23 04:00:17 +00002567// These will become non-virtual, so they always call the (virtual) onDraw... method
2568void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2569 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002570 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002571 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002572 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002573 this->onDrawText(text, byteLength, x, y, paint);
2574 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002575}
2576void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2577 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002578 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002579 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002580 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002581 this->onDrawPosText(text, byteLength, pos, paint);
2582 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002583}
2584void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2585 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002586 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002587 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002588 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002589 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2590 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002591}
2592void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2593 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002594 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002595 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002596 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002597 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2598 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002599}
reed45561a02016-07-07 12:47:17 -07002600void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2601 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002602 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002603 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002604 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002605 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2606 }
2607}
fmalita00d5c2c2014-08-21 08:53:26 -07002608void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2609 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002610 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002611 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002612 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002613 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002614}
reed@google.come0d9ce82014-04-23 04:00:17 +00002615
Ruiqi Maof5101492018-06-29 14:32:21 -04002616void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
2617 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002618 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2619
2620 while (iter.next()) {
2621 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002622 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002623 }
2624
2625 LOOPER_END
2626}
2627
dandovb3c9d1c2014-08-12 08:34:29 -07002628void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002629 const SkPoint texCoords[4], SkBlendMode bmode,
2630 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002631 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002632 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002633 return;
2634 }
mtklein6cfa73a2014-08-13 13:33:49 -07002635
Mike Reedfaba3712016-11-03 14:45:31 -04002636 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002637}
2638
2639void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002640 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002641 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002642 // Since a patch is always within the convex hull of the control points, we discard it when its
2643 // bounding rectangle is completely outside the current clip.
2644 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002645 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002646 if (this->quickReject(bounds)) {
2647 return;
2648 }
mtklein6cfa73a2014-08-13 13:33:49 -07002649
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()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002653 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, 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