blob: efdead1e67277d6a5b468e4adf6ee9f40c67c302 [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"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkDrawLooper.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040018#include "SkDrawable.h"
Herb Derby41f4f312018-06-06 17:45:53 +000019#include "SkGlyphCache.h"
20#include "SkGlyphRun.h"
piotaixrb5fae932014-09-24 13:03:30 -070021#include "SkImage.h"
senorblanco900c3672016-04-27 11:31:23 -070022#include "SkImageFilter.h"
23#include "SkImageFilterCache.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040024#include "SkImage_Base.h"
msarettc573a402016-08-02 08:05:56 -070025#include "SkLatticeIter.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040026#include "SkMSAN.h"
Mike Reed5df49342016-11-12 08:06:55 -060027#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080028#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000029#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050030#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070031#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070032#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070033#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040034#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000035#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040036#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000037#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050038#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080039#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000040#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040041#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000042#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040043#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070044#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000045#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040046#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080047#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040048#include "SkVertices.h"
49
bungemand3ebb482015-08-05 13:57:49 -070050#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000051
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080053#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050054#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000055#endif
56
reede3b38ce2016-01-08 09:18:44 -080057#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050058#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080059
Mike Reed139e5e02017-03-08 11:29:33 -050060///////////////////////////////////////////////////////////////////////////////////////////////////
61
reedc83a2972015-07-16 07:40:45 -070062/*
63 * Return true if the drawing this rect would hit every pixels in the canvas.
64 *
65 * Returns false if
66 * - rect does not contain the canvas' bounds
67 * - paint is not fill
68 * - paint would blur or otherwise change the coverage of the rect
69 */
70bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
71 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070072 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
73 (int)kNone_ShaderOverrideOpacity,
74 "need_matching_enums0");
75 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
76 (int)kOpaque_ShaderOverrideOpacity,
77 "need_matching_enums1");
78 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
79 (int)kNotOpaque_ShaderOverrideOpacity,
80 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070081
82 const SkISize size = this->getBaseLayerSize();
83 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050084
85 // if we're clipped at all, we can't overwrite the entire surface
86 {
87 SkBaseDevice* base = this->getDevice();
88 SkBaseDevice* top = this->getTopDevice();
89 if (base != top) {
90 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
91 }
92 if (!base->clipIsWideOpen()) {
93 return false;
94 }
reedc83a2972015-07-16 07:40:45 -070095 }
96
97 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070098 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070099 return false; // conservative
100 }
halcanaryc5769b22016-08-10 07:13:21 -0700101
102 SkRect devRect;
103 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
104 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700105 return false;
106 }
107 }
108
109 if (paint) {
110 SkPaint::Style paintStyle = paint->getStyle();
111 if (!(paintStyle == SkPaint::kFill_Style ||
112 paintStyle == SkPaint::kStrokeAndFill_Style)) {
113 return false;
114 }
115 if (paint->getMaskFilter() || paint->getLooper()
116 || paint->getPathEffect() || paint->getImageFilter()) {
117 return false; // conservative
118 }
119 }
120 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
121}
122
123///////////////////////////////////////////////////////////////////////////////////////////////////
124
reed@google.comda17f752012-08-16 18:27:05 +0000125// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126//#define SK_TRACE_SAVERESTORE
127
128#ifdef SK_TRACE_SAVERESTORE
129 static int gLayerCounter;
130 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
131 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
132
133 static int gRecCounter;
134 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
135 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
136
137 static int gCanvasCounter;
138 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
139 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
140#else
141 #define inc_layer()
142 #define dec_layer()
143 #define inc_rec()
144 #define dec_rec()
145 #define inc_canvas()
146 #define dec_canvas()
147#endif
148
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000149typedef SkTLazy<SkPaint> SkLazyPaint;
150
reedc83a2972015-07-16 07:40:45 -0700151void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000152 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700153 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
154 ? SkSurface::kDiscard_ContentChangeMode
155 : SkSurface::kRetain_ContentChangeMode);
156 }
157}
158
159void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
160 ShaderOverrideOpacity overrideOpacity) {
161 if (fSurfaceBase) {
162 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
163 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
164 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
165 // and therefore we don't care which mode we're in.
166 //
167 if (fSurfaceBase->outstandingImageSnapshot()) {
168 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
169 mode = SkSurface::kDiscard_ContentChangeMode;
170 }
171 }
172 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000173 }
174}
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000178/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 The clip/matrix/proc are fields that reflect the top of the save/restore
180 stack. Whenever the canvas changes, it marks a dirty flag, and then before
181 these are used (assuming we're not on a layer) we rebuild these cache
182 values: they reflect the top of the save stack, but translated and clipped
183 by the device's XY offset and bitmap-bounds.
184*/
185struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400186 DeviceCM* fNext;
187 sk_sp<SkBaseDevice> fDevice;
188 SkRasterClip fClip;
189 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
190 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400191 sk_sp<SkImage> fClipImage;
192 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193
Florin Malita53f77bd2017-04-28 13:48:37 -0400194 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000195 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700196 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400197 , fDevice(std::move(device))
198 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000200 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400201 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400202 {}
reed@google.com4b226022011-01-11 18:32:13 +0000203
mtkleinfeaadee2015-04-08 11:25:48 -0700204 void reset(const SkIRect& bounds) {
205 SkASSERT(!fPaint);
206 SkASSERT(!fNext);
207 SkASSERT(fDevice);
208 fClip.setRect(bounds);
209 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210};
211
212/* This is the record we keep for each save/restore level in the stack.
213 Since a level optionally copies the matrix and/or stack, we have pointers
214 for these fields. If the value is copied for this level, the copy is
215 stored in the ...Storage field, and the pointer points to that. If the
216 value is not copied for this level, we ignore ...Storage, and just point
217 at the corresponding value in the previous level in the stack.
218*/
219class SkCanvas::MCRec {
220public:
reedd9544982014-09-09 18:46:22 -0700221 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 /* If there are any layers in the stack, this points to the top-most
223 one that is at or below this level in the stack (so we know what
224 bitmap/device to draw into from this level. This value is NOT
225 reference counted, since the real owner is either our fLayer field,
226 or a previous one in a lower level.)
227 */
Mike Reeda1361362017-03-07 09:37:29 -0500228 DeviceCM* fTopLayer;
229 SkConservativeClip fRasterClip;
230 SkMatrix fMatrix;
231 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232
Mike Reeda1361362017-03-07 09:37:29 -0500233 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700234 fLayer = nullptr;
235 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800236 fMatrix.reset();
237 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700238
reedd9544982014-09-09 18:46:22 -0700239 // don't bother initializing fNext
240 inc_rec();
241 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400242 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700243 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700244 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800245 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700246
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 // don't bother initializing fNext
248 inc_rec();
249 }
250 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700251 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 dec_rec();
253 }
mtkleinfeaadee2015-04-08 11:25:48 -0700254
255 void reset(const SkIRect& bounds) {
256 SkASSERT(fLayer);
257 SkASSERT(fDeferredSaveCount == 0);
258
259 fMatrix.reset();
260 fRasterClip.setRect(bounds);
261 fLayer->reset(bounds);
262 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263};
264
Mike Reeda1361362017-03-07 09:37:29 -0500265class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266public:
Mike Reeda1361362017-03-07 09:37:29 -0500267 SkDrawIter(SkCanvas* canvas)
268 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
269 {}
reed@google.com4b226022011-01-11 18:32:13 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000272 const DeviceCM* rec = fCurrLayer;
273 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400274 fDevice = rec->fDevice.get();
275 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700277 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 return true;
279 }
280 return false;
281 }
reed@google.com4b226022011-01-11 18:32:13 +0000282
reed@google.com6f8f2922011-03-04 22:27:10 +0000283 int getX() const { return fDevice->getOrigin().x(); }
284 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000286
Mike Reed99330ba2017-02-22 11:01:08 -0500287 SkBaseDevice* fDevice;
288
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 const DeviceCM* fCurrLayer;
291 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292};
293
Florin Malita713b8ef2017-04-28 10:57:24 -0400294#define FOR_EACH_TOP_DEVICE( code ) \
295 do { \
296 DeviceCM* layer = fMCRec->fTopLayer; \
297 while (layer) { \
298 SkBaseDevice* device = layer->fDevice.get(); \
299 if (device) { \
300 code; \
301 } \
302 layer = layer->fNext; \
303 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500304 } while (0)
305
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306/////////////////////////////////////////////////////////////////////////////
307
reeddbc3cef2015-04-29 12:18:57 -0700308static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
309 return lazy->isValid() ? lazy->get() : lazy->set(orig);
310}
311
312/**
313 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700314 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700315 */
reedd053ce92016-03-22 10:17:23 -0700316static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700317 SkImageFilter* imgf = paint.getImageFilter();
318 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700319 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700320 }
321
reedd053ce92016-03-22 10:17:23 -0700322 SkColorFilter* imgCFPtr;
323 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700324 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700325 }
reedd053ce92016-03-22 10:17:23 -0700326 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700327
328 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700329 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700330 // there is no existing paint colorfilter, so we can just return the imagefilter's
331 return imgCF;
332 }
333
334 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
335 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500336 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700337}
338
senorblanco87e066e2015-10-28 11:23:36 -0700339/**
340 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
341 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
342 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
343 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
344 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
345 * conservative "effective" bounds based on the settings in the paint... with one exception. This
346 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
347 * deliberately ignored.
348 */
349static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
350 const SkRect& rawBounds,
351 SkRect* storage) {
352 SkPaint tmpUnfiltered(paint);
353 tmpUnfiltered.setImageFilter(nullptr);
354 if (tmpUnfiltered.canComputeFastBounds()) {
355 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
356 } else {
357 return rawBounds;
358 }
359}
360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361class AutoDrawLooper {
362public:
senorblanco87e066e2015-10-28 11:23:36 -0700363 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
364 // paint. It's used to determine the size of the offscreen layer for filters.
365 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700366 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700367 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000368 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700369 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000370 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700371 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000372 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373
reedd053ce92016-03-22 10:17:23 -0700374 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700375 if (simplifiedCF) {
376 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700377 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700378 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700379 fPaint = paint;
380 }
381
382 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700383 /**
384 * We implement ImageFilters for a given draw by creating a layer, then applying the
385 * imagefilter to the pixels of that layer (its backing surface/image), and then
386 * we call restore() to xfer that layer to the main canvas.
387 *
388 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
389 * 2. Generate the src pixels:
390 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
391 * return (fPaint). We then draw the primitive (using srcover) into a cleared
392 * buffer/surface.
393 * 3. Restore the layer created in #1
394 * The imagefilter is passed the buffer/surface from the layer (now filled with the
395 * src pixels of the primitive). It returns a new "filtered" buffer, which we
396 * draw onto the previous layer using the xfermode from the original paint.
397 */
reed@google.com8926b162012-03-23 15:36:36 +0000398 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500399 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700400 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700401 SkRect storage;
402 if (rawBounds) {
403 // Make rawBounds include all paint outsets except for those due to image filters.
404 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
405 }
reedbfd5f172016-01-07 11:28:08 -0800406 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700407 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700408 fTempLayerForImageFilter = true;
409 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000410 }
411
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000412 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500413 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000414 fIsSimple = false;
415 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700416 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000417 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400418 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000419 }
420 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000421
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700423 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000424 fCanvas->internalRestore();
425 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000426 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000428
reed@google.com4e2b3d32011-04-07 14:18:59 +0000429 const SkPaint& paint() const {
430 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400431 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000432 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000434
Ben Wagner2c312c42018-06-27 14:46:46 -0400435 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000436 if (fDone) {
437 return false;
438 } else if (fIsSimple) {
439 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000440 return !fPaint->nothingToDraw();
441 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400442 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000443 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000444 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000445
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500447 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700448 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000449 SkCanvas* fCanvas;
450 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000451 const SkPaint* fPaint;
452 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700453 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000454 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000455 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000456 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400457 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000458
Ben Wagner2c312c42018-06-27 14:46:46 -0400459 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460};
461
Ben Wagner2c312c42018-06-27 14:46:46 -0400462bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700463 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000464 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400465 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000466
reeddbc3cef2015-04-29 12:18:57 -0700467 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
468 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400469 // never want our downstream clients (i.e. devices) to see loopers
470 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000471
reed5c476fb2015-04-20 08:04:21 -0700472 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700473 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700474 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000475 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000476
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000477 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000478 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000479 return false;
480 }
reed@google.com129ec222012-05-15 13:24:09 +0000481 fPaint = paint;
482
483 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400484 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000485 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000486 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000487 return true;
488}
489
reed@android.com8a1c16f2008-12-17 15:59:43 +0000490////////// macros to place around the internal draw calls //////////////////
491
reed3aafe112016-08-18 12:45:34 -0700492#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
493 this->predrawNotify(); \
494 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400495 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800496 SkDrawIter iter(this);
497
498
Ben Wagner2c312c42018-06-27 14:46:46 -0400499#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000500 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700501 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400502 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000503 SkDrawIter iter(this);
504
Ben Wagner2c312c42018-06-27 14:46:46 -0400505#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000506 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700507 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400508 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000510
Ben Wagner2c312c42018-06-27 14:46:46 -0400511#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700512 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700513 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400514 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700515 SkDrawIter iter(this);
516
reed@google.com4e2b3d32011-04-07 14:18:59 +0000517#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000518
519////////////////////////////////////////////////////////////////////////////
520
msarettfbfa2582016-08-12 08:29:08 -0700521static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
522 if (bounds.isEmpty()) {
523 return SkRect::MakeEmpty();
524 }
525
526 // Expand bounds out by 1 in case we are anti-aliasing. We store the
527 // bounds as floats to enable a faster quick reject implementation.
528 SkRect dst;
529 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
530 return dst;
531}
532
mtkleinfeaadee2015-04-08 11:25:48 -0700533void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
534 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700535 fMCRec->reset(bounds);
536
537 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500538 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400539 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700540 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700541 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700542}
543
Herb Derbyefe39bc2018-05-01 17:06:20 -0400544void SkCanvas::init(sk_sp<SkBaseDevice> device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800545 if (device && device->forceConservativeRasterClip()) {
546 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
547 }
reed42b73eb2015-11-20 13:42:42 -0800548
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000549 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800550 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700551 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552
553 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500554 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500555 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700556 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557
reeda499f902015-05-01 09:34:31 -0700558 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
559 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400560 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700561
reed@android.com8a1c16f2008-12-17 15:59:43 +0000562 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563
halcanary96fcdcc2015-08-27 07:41:13 -0700564 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000565
reedf92c8662014-08-18 08:02:43 -0700566 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700567 // The root device and the canvas should always have the same pixel geometry
568 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800569 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700570 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500571
Mike Reedc42a1cd2017-02-14 14:25:14 -0500572 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700573 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400574
Herb Derby59d997a2018-06-07 12:44:09 -0400575 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576}
577
reed@google.comcde92112011-07-06 20:00:52 +0000578SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000579 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700580 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000581{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000582 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000583
halcanary96fcdcc2015-08-27 07:41:13 -0700584 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000585}
586
reed96a857e2015-01-25 10:33:58 -0800587SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000588 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800589 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000590{
591 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400592 this->init(sk_make_sp<SkNoPixelsDevice>(
593 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps), kDefault_InitFlags);
reedd9544982014-09-09 18:46:22 -0700594}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000595
reed78e27682014-11-19 08:04:34 -0800596SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700597 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700598 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700599{
600 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700601
Mike Reed566e53c2017-03-10 10:49:45 -0500602 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400603 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps), flags);
reedd9544982014-09-09 18:46:22 -0700604}
605
Herb Derbyefe39bc2018-05-01 17:06:20 -0400606SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000607 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700608 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000609{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000610 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700611
reedd9544982014-09-09 18:46:22 -0700612 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000613}
614
Herb Derbyefe39bc2018-05-01 17:06:20 -0400615SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device, InitFlags flags)
robertphillipsfcf78292015-06-19 11:49:52 -0700616 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700617 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700618{
619 inc_canvas();
620
621 this->init(device, flags);
622}
623
reed4a8126e2014-09-22 07:29:03 -0700624SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700625 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700626 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700627{
628 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700629
Mike Reed910ca0f2018-04-25 13:04:05 -0400630 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400631 this->init(device, kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700632}
reed29c857d2014-09-21 10:25:07 -0700633
Mike Reed356f7c22017-01-10 11:58:39 -0500634SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
635 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700636 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
637 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500638 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700639{
640 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700641
Mike Reed910ca0f2018-04-25 13:04:05 -0400642 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400643 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644}
645
Mike Reed356f7c22017-01-10 11:58:39 -0500646SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
647
Matt Sarett31f99ce2017-04-11 08:46:01 -0400648#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
649SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
650 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
651 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
652 , fAllocator(nullptr)
653{
654 inc_canvas();
655
656 SkBitmap tmp(bitmap);
657 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400658 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400659 this->init(device, kDefault_InitFlags);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400660}
661#endif
662
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663SkCanvas::~SkCanvas() {
664 // free up the contents of our deque
665 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000666
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667 this->internalRestore(); // restore the last, since we're going away
668
halcanary385fe4d2015-08-26 13:07:48 -0700669 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000670
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671 dec_canvas();
672}
673
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000674SkMetaData& SkCanvas::getMetaData() {
675 // metadata users are rare, so we lazily allocate it. If that changes we
676 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700677 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000678 fMetaData = new SkMetaData;
679 }
680 return *fMetaData;
681}
682
reed@android.com8a1c16f2008-12-17 15:59:43 +0000683///////////////////////////////////////////////////////////////////////////////
684
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000685void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700686 this->onFlush();
687}
688
689void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000690 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000691 if (device) {
692 device->flush();
693 }
694}
695
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000696SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000697 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000698 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
699}
700
senorblancoafc7cce2016-02-02 18:44:15 -0800701SkIRect SkCanvas::getTopLayerBounds() const {
702 SkBaseDevice* d = this->getTopDevice();
703 if (!d) {
704 return SkIRect::MakeEmpty();
705 }
706 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
707}
708
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000709SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000710 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000711 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400713 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000714}
715
Florin Malita0ed3b642017-01-13 16:56:38 +0000716SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400717 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000718}
719
Mike Reed353196f2017-07-21 11:01:18 -0400720bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000721 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400722 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000723}
724
Mike Reed353196f2017-07-21 11:01:18 -0400725bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
726 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400727}
728
729bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
730 SkPixmap pm;
731 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
732}
733
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000734bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400735 SkPixmap pm;
736 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700737 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000738 }
739 return false;
740}
741
Matt Sarett03dd6d52017-01-23 12:15:09 -0500742bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000743 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000744 SkBaseDevice* device = this->getDevice();
745 if (!device) {
746 return false;
747 }
748
Matt Sarett03dd6d52017-01-23 12:15:09 -0500749 // This check gives us an early out and prevents generation ID churn on the surface.
750 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
751 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
752 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
753 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000754 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000755
Matt Sarett03dd6d52017-01-23 12:15:09 -0500756 // Tell our owning surface to bump its generation ID.
757 const bool completeOverwrite =
758 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700759 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700760
Matt Sarett03dd6d52017-01-23 12:15:09 -0500761 // This can still fail, most notably in the case of a invalid color type or alpha type
762 // conversion. We could pull those checks into this function and avoid the unnecessary
763 // generation ID bump. But then we would be performing those checks twice, since they
764 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400765 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000766}
reed@google.com51df9e32010-12-23 19:29:18 +0000767
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768//////////////////////////////////////////////////////////////////////////////
769
reed2ff1fce2014-12-11 07:07:37 -0800770void SkCanvas::checkForDeferredSave() {
771 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800772 this->doSave();
773 }
774}
775
reedf0090cb2014-11-26 08:55:51 -0800776int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800777#ifdef SK_DEBUG
778 int count = 0;
779 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
780 for (;;) {
781 const MCRec* rec = (const MCRec*)iter.next();
782 if (!rec) {
783 break;
784 }
785 count += 1 + rec->fDeferredSaveCount;
786 }
787 SkASSERT(count == fSaveCount);
788#endif
789 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800790}
791
792int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800793 fSaveCount += 1;
794 fMCRec->fDeferredSaveCount += 1;
795 return this->getSaveCount() - 1; // return our prev value
796}
797
798void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800799 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700800
801 SkASSERT(fMCRec->fDeferredSaveCount > 0);
802 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800803 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800804}
805
806void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800807 if (fMCRec->fDeferredSaveCount > 0) {
808 SkASSERT(fSaveCount > 1);
809 fSaveCount -= 1;
810 fMCRec->fDeferredSaveCount -= 1;
811 } else {
812 // check for underflow
813 if (fMCStack.count() > 1) {
814 this->willRestore();
815 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700816 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800817 this->internalRestore();
818 this->didRestore();
819 }
reedf0090cb2014-11-26 08:55:51 -0800820 }
821}
822
823void SkCanvas::restoreToCount(int count) {
824 // sanity check
825 if (count < 1) {
826 count = 1;
827 }
mtkleinf0f14112014-12-12 08:46:25 -0800828
reedf0090cb2014-11-26 08:55:51 -0800829 int n = this->getSaveCount() - count;
830 for (int i = 0; i < n; ++i) {
831 this->restore();
832 }
833}
834
reed2ff1fce2014-12-11 07:07:37 -0800835void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700837 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000838 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000839
Mike Reedc42a1cd2017-02-14 14:25:14 -0500840 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841}
842
reed4960eee2015-12-18 07:09:18 -0800843bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400844 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845}
846
reed4960eee2015-12-18 07:09:18 -0800847bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700848 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500849 SkIRect clipBounds = this->getDeviceClipBounds();
850 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000851 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000852 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000853
reed96e657d2015-03-10 17:30:07 -0700854 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
855
Robert Phillips12078432018-05-17 11:17:39 -0400856 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
857 // If the image filter DAG affects transparent black then we will need to render
858 // out to the clip bounds
859 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000860 }
Robert Phillips12078432018-05-17 11:17:39 -0400861
862 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700863 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700865 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400866 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400868 inputSaveLayerBounds = clipBounds;
869 }
870
871 if (imageFilter) {
872 // expand the clip bounds by the image filter DAG to include extra content that might
873 // be required by the image filters.
874 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
875 SkImageFilter::kReverse_MapDirection,
876 &inputSaveLayerBounds);
877 }
878
879 SkIRect clippedSaveLayerBounds;
880 if (bounds) {
881 // For better or for worse, user bounds currently act as a hard clip on the layer's
882 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
883 clippedSaveLayerBounds = inputSaveLayerBounds;
884 } else {
885 // If there are no user bounds, we don't want to artificially restrict the resulting
886 // layer bounds, so allow the expanded clip bounds free reign.
887 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000888 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800889
890 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400891 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800892 if (BoundsAffectsClip(saveLayerFlags)) {
893 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
894 fMCRec->fRasterClip.setEmpty();
895 fDeviceClipBounds.setEmpty();
896 }
897 return false;
898 }
Robert Phillips12078432018-05-17 11:17:39 -0400899 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000900
reed4960eee2015-12-18 07:09:18 -0800901 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700902 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400903 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
904 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000905 }
906
907 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400908 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000909 }
Robert Phillips12078432018-05-17 11:17:39 -0400910
junov@chromium.orga907ac32012-02-24 21:54:07 +0000911 return true;
912}
913
reed4960eee2015-12-18 07:09:18 -0800914int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
915 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000916}
917
reed70ee31b2015-12-10 13:44:45 -0800918int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800919 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
920}
921
Cary Clarke041e312018-03-06 13:00:52 -0500922int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700923 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400924 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
925 // no need for the layer (or any of the draws until the matching restore()
926 this->save();
927 this->clipRect({0,0,0,0});
928 } else {
929 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
930 fSaveCount += 1;
931 this->internalSaveLayer(rec, strategy);
932 }
reed4960eee2015-12-18 07:09:18 -0800933 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800934}
935
reeda2217ef2016-07-20 06:04:34 -0700936void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500937 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500938 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700939 SkDraw draw;
940 SkRasterClip rc;
941 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
942 if (!dst->accessPixels(&draw.fDst)) {
943 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800944 }
reeda2217ef2016-07-20 06:04:34 -0700945 draw.fMatrix = &SkMatrix::I();
946 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800947
948 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500949 if (filter) {
950 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
951 }
reeda2217ef2016-07-20 06:04:34 -0700952
Mike Reedc42a1cd2017-02-14 14:25:14 -0500953 int x = src->getOrigin().x() - dstOrigin.x();
954 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700955 auto special = src->snapSpecial();
956 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400957 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700958 }
robertphillips7354a4b2015-12-16 05:08:27 -0800959}
reed70ee31b2015-12-10 13:44:45 -0800960
Mike Kleine083f7c2018-02-07 12:54:27 -0500961static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500962 // Need to force L32 for now if we have an image filter.
963 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
964 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500965 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800966 }
Mike Klein649fb732018-02-26 15:09:16 -0500967
968 SkColorType ct = prev.colorType();
969 if (prev.bytesPerPixel() <= 4) {
970 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
971 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
972 ct = kN32_SkColorType;
973 }
974 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800975}
976
reed4960eee2015-12-18 07:09:18 -0800977void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700978 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800979 const SkRect* bounds = rec.fBounds;
980 const SkPaint* paint = rec.fPaint;
981 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
982
reed8c30a812016-04-20 16:36:51 -0700983 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400984 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700985 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400986 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700987 SkMatrix remainder;
988 SkSize scale;
989 /*
990 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
991 * but they do handle scaling. To accommodate this, we do the following:
992 *
993 * 1. Stash off the current CTM
994 * 2. Decompose the CTM into SCALE and REMAINDER
995 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
996 * contains the REMAINDER
997 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
998 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
999 * of the original imagefilter, and draw that (via drawSprite)
1000 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1001 *
1002 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1003 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1004 */
reed96a04f32016-04-25 09:25:15 -07001005 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001006 stashedMatrix.decomposeScale(&scale, &remainder))
1007 {
1008 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001009 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001010 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1011 SkPaint* p = lazyP.set(*paint);
1012 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1013 SkFilterQuality::kLow_SkFilterQuality,
1014 sk_ref_sp(imageFilter)));
1015 imageFilter = p->getImageFilter();
1016 paint = p;
1017 }
reed8c30a812016-04-20 16:36:51 -07001018
junov@chromium.orga907ac32012-02-24 21:54:07 +00001019 // do this before we create the layer. We don't call the public save() since
1020 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001021 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001022
junov@chromium.orga907ac32012-02-24 21:54:07 +00001023 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001024 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001025 if (modifiedRec) {
1026 // In this case there will be no layer in which to stash the matrix so we need to
1027 // revert the prior MCRec to its earlier state.
1028 modifiedRec->fMatrix = stashedMatrix;
1029 }
reed2ff1fce2014-12-11 07:07:37 -08001030 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001031 }
1032
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001033 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1034 // the clipRectBounds() call above?
1035 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001036 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001037 }
1038
reed8dc0ccb2015-03-20 06:32:52 -07001039 SkPixelGeometry geo = fProps.pixelGeometry();
1040 if (paint) {
reed76033be2015-03-14 10:54:31 -07001041 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001042 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001043 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001044 }
1045 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001046
robertphillips5139e502016-07-19 05:10:40 -07001047 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001048 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001049 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001050 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001051 }
reedb2db8982014-11-13 12:41:02 -08001052
Mike Kleine083f7c2018-02-07 12:54:27 -05001053 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001054
Hal Canary704cd322016-11-07 14:13:52 -05001055 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001056 {
reed70ee31b2015-12-10 13:44:45 -08001057 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001058 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001059 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001060 const bool trackCoverage =
1061 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001062 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001063 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001064 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001065 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001066 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1067 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001068 return;
reed61f501f2015-04-29 08:34:00 -07001069 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001070 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001071 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072
Mike Reedb43a3e02017-02-11 10:18:58 -05001073 // only have a "next" if this new layer doesn't affect the clip (rare)
1074 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001075 fMCRec->fLayer = layer;
1076 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001077
Mike Reedc61abee2017-02-28 17:45:27 -05001078 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001079 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001080 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001081 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001082
Mike Reedc42a1cd2017-02-14 14:25:14 -05001083 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1084
1085 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1086 if (layer->fNext) {
1087 // need to punch a hole in the previous device, so we don't draw there, given that
1088 // the new top-layer will allow drawing to happen "below" it.
1089 SkRegion hole(ir);
1090 do {
1091 layer = layer->fNext;
1092 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1093 } while (layer->fNext);
1094 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095}
1096
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001097int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001098 if (0xFF == alpha) {
1099 return this->saveLayer(bounds, nullptr);
1100 } else {
1101 SkPaint tmpPaint;
1102 tmpPaint.setAlpha(alpha);
1103 return this->saveLayer(bounds, &tmpPaint);
1104 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001105}
1106
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107void SkCanvas::internalRestore() {
1108 SkASSERT(fMCStack.count() != 0);
1109
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001110 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111 DeviceCM* layer = fMCRec->fLayer; // may be null
1112 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001113 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001114
1115 // now do the normal restore()
1116 fMCRec->~MCRec(); // balanced in save()
1117 fMCStack.pop_back();
1118 fMCRec = (MCRec*)fMCStack.back();
1119
Mike Reedc42a1cd2017-02-14 14:25:14 -05001120 if (fMCRec) {
1121 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1122 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001123
reed@android.com8a1c16f2008-12-17 15:59:43 +00001124 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1125 since if we're being recorded, we don't want to record this (the
1126 recorder will have already recorded the restore).
1127 */
bsalomon49f085d2014-09-05 13:34:00 -07001128 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001129 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001130 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001131 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001132 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001133 layer->fPaint.get(),
1134 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001135 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001136 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001137 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001138 delete layer;
reedb679ca82015-04-07 04:40:48 -07001139 } else {
1140 // we're at the root
reeda499f902015-05-01 09:34:31 -07001141 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001142 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001143 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001145 }
msarettfbfa2582016-08-12 08:29:08 -07001146
1147 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001148 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001149 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1150 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151}
1152
reede8f30622016-03-23 18:59:25 -07001153sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001154 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001155 props = &fProps;
1156 }
1157 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001158}
1159
reede8f30622016-03-23 18:59:25 -07001160sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001161 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001162 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001163}
1164
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001165SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001166 return this->onImageInfo();
1167}
1168
1169SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001170 SkBaseDevice* dev = this->getDevice();
1171 if (dev) {
1172 return dev->imageInfo();
1173 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001174 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001175 }
1176}
1177
brianosman898235c2016-04-06 07:38:23 -07001178bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001179 return this->onGetProps(props);
1180}
1181
1182bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001183 SkBaseDevice* dev = this->getDevice();
1184 if (dev) {
1185 if (props) {
1186 *props = fProps;
1187 }
1188 return true;
1189 } else {
1190 return false;
1191 }
1192}
1193
reed6ceeebd2016-03-09 14:26:26 -08001194bool SkCanvas::peekPixels(SkPixmap* pmap) {
1195 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001196}
1197
reed884e97c2015-05-26 11:31:54 -07001198bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001199 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001200 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001201}
1202
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001203void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001204 SkPixmap pmap;
1205 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001206 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001207 }
1208 if (info) {
1209 *info = pmap.info();
1210 }
1211 if (rowBytes) {
1212 *rowBytes = pmap.rowBytes();
1213 }
1214 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001215 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001216 }
reed884e97c2015-05-26 11:31:54 -07001217 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001218}
1219
reed884e97c2015-05-26 11:31:54 -07001220bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001221 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001222 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001223}
1224
reed@android.com8a1c16f2008-12-17 15:59:43 +00001225/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226
Florin Malita53f77bd2017-04-28 13:48:37 -04001227void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1228 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001229 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001230 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001231 paint = &tmp;
1232 }
reed@google.com4b226022011-01-11 18:32:13 +00001233
Ben Wagner2c312c42018-06-27 14:46:46 -04001234 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001235
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001237 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001238 paint = &looper.paint();
1239 SkImageFilter* filter = paint->getImageFilter();
1240 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001241 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001242 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1243 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001244 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1245 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001246 }
reed@google.com76dd2772012-01-05 21:15:07 +00001247 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001248 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001249 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001250 }
reeda2217ef2016-07-20 06:04:34 -07001251
reed@google.com4e2b3d32011-04-07 14:18:59 +00001252 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253}
1254
reed32704672015-12-16 08:27:10 -08001255/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001256
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001257void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001258 if (dx || dy) {
1259 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001260 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001261
reedfe69b502016-09-12 06:31:48 -07001262 // Translate shouldn't affect the is-scale-translateness of the matrix.
1263 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001264
Mike Reedc42a1cd2017-02-14 14:25:14 -05001265 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001266
reedfe69b502016-09-12 06:31:48 -07001267 this->didTranslate(dx,dy);
1268 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001269}
1270
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001271void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001272 SkMatrix m;
1273 m.setScale(sx, sy);
1274 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275}
1276
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001277void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001278 SkMatrix m;
1279 m.setRotate(degrees);
1280 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281}
1282
bungeman7438bfc2016-07-12 15:01:19 -07001283void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1284 SkMatrix m;
1285 m.setRotate(degrees, px, py);
1286 this->concat(m);
1287}
1288
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001289void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001290 SkMatrix m;
1291 m.setSkew(sx, sy);
1292 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001293}
1294
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001295void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001296 if (matrix.isIdentity()) {
1297 return;
1298 }
1299
reed2ff1fce2014-12-11 07:07:37 -08001300 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001301 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001302 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001303
Mike Reed7627fa52017-02-08 10:07:53 -05001304 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001305
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001306 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001307}
1308
reed8c30a812016-04-20 16:36:51 -07001309void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001310 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001311 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001312
Mike Reedc42a1cd2017-02-14 14:25:14 -05001313 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001314}
1315
1316void SkCanvas::setMatrix(const SkMatrix& matrix) {
1317 this->checkForDeferredSave();
1318 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001319 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320}
1321
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001323 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324}
1325
1326//////////////////////////////////////////////////////////////////////////////
1327
Mike Reedc1f77742016-12-09 09:00:50 -05001328void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001329 if (!rect.isFinite()) {
1330 return;
1331 }
reed2ff1fce2014-12-11 07:07:37 -08001332 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001333 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1334 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001335}
1336
Mike Reedc1f77742016-12-09 09:00:50 -05001337void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001338 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001339
Mike Reed7627fa52017-02-08 10:07:53 -05001340 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001341
reedc64eff52015-11-21 12:39:45 -08001342 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001343 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1344 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001345 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346}
1347
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001348void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1349 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001350 if (fClipRestrictionRect.isEmpty()) {
1351 // we notify the device, but we *dont* resolve deferred saves (since we're just
1352 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001353 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001354 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001355 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001356 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001357 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001358 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001359 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1360 }
1361}
1362
Mike Reedc1f77742016-12-09 09:00:50 -05001363void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001364 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001365 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001366 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001367 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1368 } else {
1369 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001370 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001371}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001372
Mike Reedc1f77742016-12-09 09:00:50 -05001373void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001374 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001375
Brian Salomona3b45d42016-10-03 11:36:16 -04001376 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001377
Mike Reed7627fa52017-02-08 10:07:53 -05001378 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001379
Mike Reed20800c82017-11-15 16:09:04 -05001380 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1381 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001382 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001383}
1384
Mike Reedc1f77742016-12-09 09:00:50 -05001385void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001386 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001387 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001388
1389 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1390 SkRect r;
1391 if (path.isRect(&r)) {
1392 this->onClipRect(r, op, edgeStyle);
1393 return;
1394 }
1395 SkRRect rrect;
1396 if (path.isOval(&r)) {
1397 rrect.setOval(r);
1398 this->onClipRRect(rrect, op, edgeStyle);
1399 return;
1400 }
1401 if (path.isRRect(&rrect)) {
1402 this->onClipRRect(rrect, op, edgeStyle);
1403 return;
1404 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001405 }
robertphillips39f05382015-11-24 09:30:12 -08001406
1407 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001408}
1409
Mike Reedc1f77742016-12-09 09:00:50 -05001410void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001411 AutoValidateClip avc(this);
1412
Brian Salomona3b45d42016-10-03 11:36:16 -04001413 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001414
Mike Reed7627fa52017-02-08 10:07:53 -05001415 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416
Brian Salomona3b45d42016-10-03 11:36:16 -04001417 const SkPath* rasterClipPath = &path;
1418 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001419 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1420 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001421 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422}
1423
Mike Reedc1f77742016-12-09 09:00:50 -05001424void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001425 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001426 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001427}
1428
Mike Reedc1f77742016-12-09 09:00:50 -05001429void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001430 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001431
reed@google.com5c3d1472011-02-22 19:12:23 +00001432 AutoValidateClip avc(this);
1433
Mike Reed20800c82017-11-15 16:09:04 -05001434 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001435 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436}
1437
reed@google.com819c9212011-02-23 18:56:55 +00001438#ifdef SK_DEBUG
1439void SkCanvas::validateClip() const {
1440 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001441 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001442 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001443 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001444 return;
1445 }
reed@google.com819c9212011-02-23 18:56:55 +00001446}
1447#endif
1448
Mike Reeda1361362017-03-07 09:37:29 -05001449bool SkCanvas::androidFramework_isClipAA() const {
1450 bool containsAA = false;
1451
1452 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1453
1454 return containsAA;
1455}
1456
1457class RgnAccumulator {
1458 SkRegion* fRgn;
1459public:
1460 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1461 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1462 SkIPoint origin = device->getOrigin();
1463 if (origin.x() | origin.y()) {
1464 rgn->translate(origin.x(), origin.y());
1465 }
1466 fRgn->op(*rgn, SkRegion::kUnion_Op);
1467 }
1468};
1469
1470void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1471 RgnAccumulator accum(rgn);
1472 SkRegion tmp;
1473
1474 rgn->setEmpty();
1475 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001476}
1477
reed@google.com5c3d1472011-02-22 19:12:23 +00001478///////////////////////////////////////////////////////////////////////////////
1479
reed@google.com754de5f2014-02-24 19:38:20 +00001480bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001481 return fMCRec->fRasterClip.isEmpty();
1482
1483 // TODO: should we only use the conservative answer in a recording canvas?
1484#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001485 SkBaseDevice* dev = this->getTopDevice();
1486 // if no device we return true
1487 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001488#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001489}
1490
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001491bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001492 SkBaseDevice* dev = this->getTopDevice();
1493 // if no device we return false
1494 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001495}
1496
msarettfbfa2582016-08-12 08:29:08 -07001497static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1498#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1499 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1500 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1501 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1502 return 0xF != _mm_movemask_ps(mask);
1503#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1504 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1505 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1506 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1507 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1508#else
1509 SkRect devRectAsRect;
1510 SkRect devClipAsRect;
1511 devRect.store(&devRectAsRect.fLeft);
1512 devClip.store(&devClipAsRect.fLeft);
1513 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1514#endif
1515}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001516
msarettfbfa2582016-08-12 08:29:08 -07001517// It's important for this function to not be inlined. Otherwise the compiler will share code
1518// between the fast path and the slow path, resulting in two slow paths.
1519static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1520 const SkMatrix& matrix) {
1521 SkRect deviceRect;
1522 matrix.mapRect(&deviceRect, src);
1523 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1524}
1525
1526bool SkCanvas::quickReject(const SkRect& src) const {
1527#ifdef SK_DEBUG
1528 // Verify that fDeviceClipBounds are set properly.
1529 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001530 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001531 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001532 } else {
msarettfbfa2582016-08-12 08:29:08 -07001533 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001534 }
msarettfbfa2582016-08-12 08:29:08 -07001535
msarett9637ea92016-08-18 14:03:30 -07001536 // Verify that fIsScaleTranslate is set properly.
1537 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001538#endif
1539
msarett9637ea92016-08-18 14:03:30 -07001540 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001541 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1542 }
1543
1544 // We inline the implementation of mapScaleTranslate() for the fast path.
1545 float sx = fMCRec->fMatrix.getScaleX();
1546 float sy = fMCRec->fMatrix.getScaleY();
1547 float tx = fMCRec->fMatrix.getTranslateX();
1548 float ty = fMCRec->fMatrix.getTranslateY();
1549 Sk4f scale(sx, sy, sx, sy);
1550 Sk4f trans(tx, ty, tx, ty);
1551
1552 // Apply matrix.
1553 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1554
1555 // Make sure left < right, top < bottom.
1556 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1557 Sk4f min = Sk4f::Min(ltrb, rblt);
1558 Sk4f max = Sk4f::Max(ltrb, rblt);
1559 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1560 // ARM this sequence generates the fastest (a single instruction).
1561 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1562
1563 // Check if the device rect is NaN or outside the clip.
1564 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001565}
1566
reed@google.com3b3e8952012-08-16 20:53:31 +00001567bool SkCanvas::quickReject(const SkPath& path) const {
1568 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001569}
1570
Mike Klein83c8dd92017-11-28 17:08:45 -05001571SkRect SkCanvas::getLocalClipBounds() const {
1572 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001573 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001574 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001575 }
1576
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001577 SkMatrix inverse;
1578 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001579 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001580 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001581 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582
Mike Reed42e8c532017-01-23 14:09:13 -05001583 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001584 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001585 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001586
Mike Reedb57b9312018-04-23 12:12:54 -04001587 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001588 inverse.mapRect(&bounds, r);
1589 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001590}
1591
Mike Klein83c8dd92017-11-28 17:08:45 -05001592SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001593 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001594}
1595
reed@android.com8a1c16f2008-12-17 15:59:43 +00001596const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001597 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001598}
1599
Brian Osman11052242016-10-27 14:47:55 -04001600GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001601 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001602 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001603}
1604
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001605GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001606 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001607 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001608}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001609
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001610void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1611 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001612 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001613 if (outer.isEmpty()) {
1614 return;
1615 }
1616 if (inner.isEmpty()) {
1617 this->drawRRect(outer, paint);
1618 return;
1619 }
1620
1621 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001622 // be able to return ...
1623 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001624 //
1625 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001626 if (!outer.getBounds().contains(inner.getBounds())) {
1627 return;
1628 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001629
1630 this->onDrawDRRect(outer, inner, paint);
1631}
1632
reed41af9662015-01-05 07:49:08 -08001633void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001634 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001635 this->onDrawPaint(paint);
1636}
1637
1638void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001639 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001640 // To avoid redundant logic in our culling code and various backends, we always sort rects
1641 // before passing them along.
1642 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001643}
1644
msarettdca352e2016-08-26 06:37:45 -07001645void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001646 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001647 if (region.isEmpty()) {
1648 return;
1649 }
1650
1651 if (region.isRect()) {
1652 return this->drawIRect(region.getBounds(), paint);
1653 }
1654
1655 this->onDrawRegion(region, paint);
1656}
1657
reed41af9662015-01-05 07:49:08 -08001658void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001659 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001660 // To avoid redundant logic in our culling code and various backends, we always sort rects
1661 // before passing them along.
1662 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001663}
1664
1665void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001666 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001667 this->onDrawRRect(rrect, paint);
1668}
1669
1670void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001671 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001672 this->onDrawPoints(mode, count, pts, paint);
1673}
1674
Mike Reede88a1cb2017-03-17 09:50:46 -04001675void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1676 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001677 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001678 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001679 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1680 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001681 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001682}
1683
1684void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001685 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001686 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001687 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1688}
1689
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001690void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1691 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001692 TRACE_EVENT0("skia", TRACE_FUNC);
1693 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001694 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001695 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1696}
1697
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001698void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1699 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001700 TRACE_EVENT0("skia", TRACE_FUNC);
1701 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001702 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001703 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001704}
1705
1706void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001707 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001708 this->onDrawPath(path, paint);
1709}
1710
reeda85d4d02015-05-06 12:56:48 -07001711void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001712 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001713 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001714 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001715}
1716
Mike Reedc4e31092018-01-30 11:15:27 -05001717// Returns true if the rect can be "filled" : non-empty and finite
1718static bool fillable(const SkRect& r) {
1719 SkScalar w = r.width();
1720 SkScalar h = r.height();
1721 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1722}
1723
reede47829b2015-08-06 10:02:53 -07001724void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1725 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001726 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001727 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001728 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001729 return;
1730 }
1731 this->onDrawImageRect(image, &src, dst, paint, constraint);
1732}
reed41af9662015-01-05 07:49:08 -08001733
reed84984ef2015-07-17 07:09:43 -07001734void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1735 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001736 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001737 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001738}
1739
reede47829b2015-08-06 10:02:53 -07001740void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1741 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001742 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001743 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1744 constraint);
1745}
reede47829b2015-08-06 10:02:53 -07001746
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001747namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001748class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001749public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001750 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1751 if (!origPaint) {
1752 return;
1753 }
1754 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1755 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1756 }
1757 if (origPaint->getMaskFilter()) {
1758 fPaint.writable()->setMaskFilter(nullptr);
1759 }
1760 if (origPaint->isAntiAlias()) {
1761 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001762 }
1763 }
1764
1765 const SkPaint* get() const {
1766 return fPaint;
1767 }
1768
1769private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001770 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001771};
1772} // namespace
1773
reed4c21dc52015-06-25 12:32:03 -07001774void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1775 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001776 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001777 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001778 if (dst.isEmpty()) {
1779 return;
1780 }
msarett552bca92016-08-03 06:53:26 -07001781 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001782 LatticePaint latticePaint(paint);
1783 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001784 } else {
reede47829b2015-08-06 10:02:53 -07001785 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001786 }
reed4c21dc52015-06-25 12:32:03 -07001787}
1788
msarett16882062016-08-16 09:31:08 -07001789void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1790 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001791 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001792 RETURN_ON_NULL(image);
1793 if (dst.isEmpty()) {
1794 return;
1795 }
msarett71df2d72016-09-30 12:41:42 -07001796
1797 SkIRect bounds;
1798 Lattice latticePlusBounds = lattice;
1799 if (!latticePlusBounds.fBounds) {
1800 bounds = SkIRect::MakeWH(image->width(), image->height());
1801 latticePlusBounds.fBounds = &bounds;
1802 }
1803
1804 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001805 LatticePaint latticePaint(paint);
1806 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001807 } else {
1808 this->drawImageRect(image, dst, paint);
1809 }
1810}
1811
reed41af9662015-01-05 07:49:08 -08001812void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001813 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001814 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001815 return;
1816 }
reed41af9662015-01-05 07:49:08 -08001817 this->onDrawBitmap(bitmap, dx, dy, paint);
1818}
1819
reede47829b2015-08-06 10:02:53 -07001820void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001821 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001822 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001823 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001824 return;
1825 }
reede47829b2015-08-06 10:02:53 -07001826 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001827}
1828
reed84984ef2015-07-17 07:09:43 -07001829void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1830 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001831 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001832}
1833
reede47829b2015-08-06 10:02:53 -07001834void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1835 SrcRectConstraint constraint) {
1836 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1837 constraint);
1838}
reede47829b2015-08-06 10:02:53 -07001839
reed41af9662015-01-05 07:49:08 -08001840void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1841 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001842 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001843 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001844 return;
1845 }
msarett552bca92016-08-03 06:53:26 -07001846 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001847 LatticePaint latticePaint(paint);
1848 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001849 } else {
reeda5517e22015-07-14 10:54:12 -07001850 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001851 }
reed41af9662015-01-05 07:49:08 -08001852}
1853
msarettc573a402016-08-02 08:05:56 -07001854void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1855 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001856 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001857 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001858 return;
1859 }
msarett71df2d72016-09-30 12:41:42 -07001860
1861 SkIRect bounds;
1862 Lattice latticePlusBounds = lattice;
1863 if (!latticePlusBounds.fBounds) {
1864 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1865 latticePlusBounds.fBounds = &bounds;
1866 }
1867
1868 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001869 LatticePaint latticePaint(paint);
1870 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001871 } else {
msarett16882062016-08-16 09:31:08 -07001872 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001873 }
msarettc573a402016-08-02 08:05:56 -07001874}
1875
reed71c3c762015-06-24 10:29:17 -07001876void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001877 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001878 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001879 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001880 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001881 if (count <= 0) {
1882 return;
1883 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001884 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001885 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001886 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001887}
1888
reedf70b5312016-03-04 16:36:20 -08001889void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001890 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001891 if (key) {
1892 this->onDrawAnnotation(rect, key, value);
1893 }
1894}
1895
reede47829b2015-08-06 10:02:53 -07001896void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1897 const SkPaint* paint, SrcRectConstraint constraint) {
1898 if (src) {
1899 this->drawImageRect(image, *src, dst, paint, constraint);
1900 } else {
1901 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1902 dst, paint, constraint);
1903 }
1904}
1905void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1906 const SkPaint* paint, SrcRectConstraint constraint) {
1907 if (src) {
1908 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1909 } else {
1910 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1911 dst, paint, constraint);
1912 }
1913}
1914
Mike Reed4204da22017-05-17 08:53:36 -04001915void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001916 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001917 this->onDrawShadowRec(path, rec);
1918}
1919
1920void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1921 SkPaint paint;
1922 const SkRect& pathBounds = path.getBounds();
1923
Ben Wagner2c312c42018-06-27 14:46:46 -04001924 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001925 while (iter.next()) {
1926 iter.fDevice->drawShadow(path, rec);
1927 }
1928 LOOPER_END
1929}
1930
reed@android.com8a1c16f2008-12-17 15:59:43 +00001931//////////////////////////////////////////////////////////////////////////////
1932// These are the virtual drawing methods
1933//////////////////////////////////////////////////////////////////////////////
1934
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001935void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001936 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001937 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1938 }
1939}
1940
reed41af9662015-01-05 07:49:08 -08001941void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001942 this->internalDrawPaint(paint);
1943}
1944
1945void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001946 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001947
1948 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001949 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001950 }
1951
reed@google.com4e2b3d32011-04-07 14:18:59 +00001952 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001953}
1954
reed41af9662015-01-05 07:49:08 -08001955void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1956 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001957 if ((long)count <= 0) {
1958 return;
1959 }
1960
Mike Reed822128b2017-02-28 16:41:03 -05001961 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001962 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001963 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001964 // special-case 2 points (common for drawing a single line)
1965 if (2 == count) {
1966 r.set(pts[0], pts[1]);
1967 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001968 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001969 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001970 if (!r.isFinite()) {
1971 return;
1972 }
Mike Reed822128b2017-02-28 16:41:03 -05001973 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001974 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1975 return;
1976 }
1977 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001978 }
reed@google.coma584aed2012-05-16 14:06:02 +00001979
halcanary96fcdcc2015-08-27 07:41:13 -07001980 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001981
Ben Wagner2c312c42018-06-27 14:46:46 -04001982 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001983
reed@android.com8a1c16f2008-12-17 15:59:43 +00001984 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001985 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001986 }
reed@google.com4b226022011-01-11 18:32:13 +00001987
reed@google.com4e2b3d32011-04-07 14:18:59 +00001988 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001989}
1990
reed4a167172016-08-18 17:15:25 -07001991static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1992 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07001993 (intptr_t)paint.getLooper() ) != 0;
1994}
1995
reed41af9662015-01-05 07:49:08 -08001996void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001997 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001999 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002000 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002001 return;
2002 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002003 }
reed@google.com4b226022011-01-11 18:32:13 +00002004
reed4a167172016-08-18 17:15:25 -07002005 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002006 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002007
reed4a167172016-08-18 17:15:25 -07002008 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002009 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002010 }
2011
2012 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002013 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002014 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002015 SkDrawIter iter(this);
2016 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002017 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002018 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002019 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002020}
2021
msarett44df6512016-08-25 13:54:30 -07002022void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002023 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002024 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002025 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002026 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2027 return;
2028 }
msarett44df6512016-08-25 13:54:30 -07002029 }
2030
Ben Wagner2c312c42018-06-27 14:46:46 -04002031 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002032
2033 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002034 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002035 }
2036
2037 LOOPER_END
2038}
2039
reed41af9662015-01-05 07:49:08 -08002040void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002041 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002042 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002043 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002044 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002045 return;
2046 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002047 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002048
Ben Wagner2c312c42018-06-27 14:46:46 -04002049 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002050
2051 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002052 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002053 }
2054
2055 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002056}
2057
bsalomonac3aa242016-08-19 11:25:19 -07002058void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2059 SkScalar sweepAngle, bool useCenter,
2060 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002061 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002062 if (paint.canComputeFastBounds()) {
2063 SkRect storage;
2064 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002065 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002066 return;
2067 }
bsalomonac3aa242016-08-19 11:25:19 -07002068 }
2069
Ben Wagner2c312c42018-06-27 14:46:46 -04002070 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002071
2072 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002073 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002074 }
2075
2076 LOOPER_END
2077}
2078
reed41af9662015-01-05 07:49:08 -08002079void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002080 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002081 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002082 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2083 return;
2084 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002085 }
2086
2087 if (rrect.isRect()) {
2088 // call the non-virtual version
2089 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002090 return;
2091 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002092 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002093 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2094 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002095 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002096
Ben Wagner2c312c42018-06-27 14:46:46 -04002097 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002098
2099 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002100 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002101 }
2102
2103 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002104}
2105
Mike Reed822128b2017-02-28 16:41:03 -05002106void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +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(outer.getBounds(), &storage))) {
2110 return;
2111 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002112 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002113
Ben Wagner2c312c42018-06-27 14:46:46 -04002114 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002115
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002116 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002117 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002118 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002119
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002120 LOOPER_END
2121}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002122
reed41af9662015-01-05 07:49:08 -08002123void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002124 if (!path.isFinite()) {
2125 return;
2126 }
2127
Mike Reed822128b2017-02-28 16:41:03 -05002128 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002129 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002130 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002131 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2132 return;
2133 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002134 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002135
Mike Reed822128b2017-02-28 16:41:03 -05002136 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002137 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002138 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002139 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002140 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002141 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002142
Ben Wagner2c312c42018-06-27 14:46:46 -04002143 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002144
2145 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002146 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002147 }
2148
reed@google.com4e2b3d32011-04-07 14:18:59 +00002149 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002150}
2151
reed262a71b2015-12-05 13:07:27 -08002152bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002153 if (!paint.getImageFilter()) {
2154 return false;
2155 }
2156
2157 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002158 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002159 return false;
2160 }
2161
2162 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2163 // Once we can filter and the filter will return a result larger than itself, we should be
2164 // able to remove this constraint.
2165 // skbug.com/4526
2166 //
2167 SkPoint pt;
2168 ctm.mapXY(x, y, &pt);
2169 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2170 return ir.contains(fMCRec->fRasterClip.getBounds());
2171}
2172
Mike Reedf441cfc2018-04-11 14:50:16 -04002173// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2174// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2175// null.
2176static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2177 if (paintParam) {
2178 *real = *paintParam;
2179 real->setStyle(SkPaint::kFill_Style);
2180 real->setPathEffect(nullptr);
2181 paintParam = real;
2182 }
2183 return paintParam;
2184}
2185
reeda85d4d02015-05-06 12:56:48 -07002186void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002187 SkPaint realPaint;
2188 paint = init_image_paint(&realPaint, paint);
2189
reeda85d4d02015-05-06 12:56:48 -07002190 SkRect bounds = SkRect::MakeXYWH(x, y,
2191 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002192 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002193 SkRect tmp = bounds;
2194 if (paint) {
2195 paint->computeFastBounds(tmp, &tmp);
2196 }
2197 if (this->quickReject(tmp)) {
2198 return;
2199 }
reeda85d4d02015-05-06 12:56:48 -07002200 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002201 // At this point we need a real paint object. If the caller passed null, then we should
2202 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2203 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2204 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002205
reeda2217ef2016-07-20 06:04:34 -07002206 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002207 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2208 *paint);
2209 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002210 special = this->getDevice()->makeSpecial(image);
2211 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002212 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002213 }
2214 }
2215
reed262a71b2015-12-05 13:07:27 -08002216 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2217
reeda85d4d02015-05-06 12:56:48 -07002218 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002219 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002220 if (special) {
2221 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002222 iter.fDevice->ctm().mapXY(x, y, &pt);
2223 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002224 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002225 SkScalarRoundToInt(pt.fY), pnt,
2226 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002227 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002228 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002229 }
reeda85d4d02015-05-06 12:56:48 -07002230 }
halcanary9d524f22016-03-29 09:03:52 -07002231
reeda85d4d02015-05-06 12:56:48 -07002232 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002233}
2234
reed41af9662015-01-05 07:49:08 -08002235void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002236 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002237 SkPaint realPaint;
2238 paint = init_image_paint(&realPaint, paint);
2239
halcanary96fcdcc2015-08-27 07:41:13 -07002240 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002241 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002242 if (paint) {
2243 paint->computeFastBounds(dst, &storage);
2244 }
2245 if (this->quickReject(storage)) {
2246 return;
2247 }
reeda85d4d02015-05-06 12:56:48 -07002248 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002249 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002250
Ben Wagner2c312c42018-06-27 14:46:46 -04002251 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002252
reeda85d4d02015-05-06 12:56:48 -07002253 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002254 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002255 }
halcanary9d524f22016-03-29 09:03:52 -07002256
reeda85d4d02015-05-06 12:56:48 -07002257 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002258}
2259
reed41af9662015-01-05 07:49:08 -08002260void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002261 SkDEBUGCODE(bitmap.validate();)
2262
reed33366972015-10-08 09:22:02 -07002263 if (bitmap.drawsNothing()) {
2264 return;
2265 }
2266
Mike Reedf441cfc2018-04-11 14:50:16 -04002267 SkPaint realPaint;
2268 init_image_paint(&realPaint, paint);
2269 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002270
Mike Reed822128b2017-02-28 16:41:03 -05002271 SkRect bounds;
2272 bitmap.getBounds(&bounds);
2273 bounds.offset(x, y);
2274 bool canFastBounds = paint->canComputeFastBounds();
2275 if (canFastBounds) {
2276 SkRect storage;
2277 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002278 return;
2279 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002280 }
reed@google.com4b226022011-01-11 18:32:13 +00002281
reeda2217ef2016-07-20 06:04:34 -07002282 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002283 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2284 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002285 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002286 special = this->getDevice()->makeSpecial(bitmap);
2287 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002288 drawAsSprite = false;
2289 }
2290 }
2291
Mike Reed822128b2017-02-28 16:41:03 -05002292 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002293
2294 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002295 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002296 if (special) {
reed262a71b2015-12-05 13:07:27 -08002297 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002298 iter.fDevice->ctm().mapXY(x, y, &pt);
2299 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002300 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002301 SkScalarRoundToInt(pt.fY), pnt,
2302 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002303 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002304 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002305 }
reed33366972015-10-08 09:22:02 -07002306 }
msarettfbfa2582016-08-12 08:29:08 -07002307
reed33366972015-10-08 09:22:02 -07002308 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002309}
2310
reed@google.com9987ec32011-09-07 11:57:52 +00002311// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002312void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002313 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002314 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002315 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002316 return;
2317 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002318
halcanary96fcdcc2015-08-27 07:41:13 -07002319 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002320 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002321 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2322 return;
2323 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 }
reed@google.com3d608122011-11-21 15:16:16 +00002325
reed@google.com33535f32012-09-25 15:37:50 +00002326 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002327 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002328 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002329 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002330
Ben Wagner2c312c42018-06-27 14:46:46 -04002331 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002332
reed@google.com33535f32012-09-25 15:37:50 +00002333 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002334 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002335 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002336
reed@google.com33535f32012-09-25 15:37:50 +00002337 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002338}
2339
reed41af9662015-01-05 07:49:08 -08002340void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002341 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002342 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002343 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002344}
2345
reed4c21dc52015-06-25 12:32:03 -07002346void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2347 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002348 SkPaint realPaint;
2349 paint = init_image_paint(&realPaint, paint);
2350
halcanary96fcdcc2015-08-27 07:41:13 -07002351 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002352 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002353 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2354 return;
2355 }
reed@google.com3d608122011-11-21 15:16:16 +00002356 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002357 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002358
Ben Wagner2c312c42018-06-27 14:46:46 -04002359 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002360
reed4c21dc52015-06-25 12:32:03 -07002361 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002362 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002363 }
halcanary9d524f22016-03-29 09:03:52 -07002364
reed4c21dc52015-06-25 12:32:03 -07002365 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002366}
2367
reed41af9662015-01-05 07:49:08 -08002368void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2369 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002370 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002371 SkPaint realPaint;
2372 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002373
halcanary96fcdcc2015-08-27 07:41:13 -07002374 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002375 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002376 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2377 return;
2378 }
reed4c21dc52015-06-25 12:32:03 -07002379 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002380 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002381
Ben Wagner2c312c42018-06-27 14:46:46 -04002382 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002383
reed4c21dc52015-06-25 12:32:03 -07002384 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002385 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002386 }
halcanary9d524f22016-03-29 09:03:52 -07002387
reed4c21dc52015-06-25 12:32:03 -07002388 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002389}
2390
msarett16882062016-08-16 09:31:08 -07002391void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2392 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002393 SkPaint realPaint;
2394 paint = init_image_paint(&realPaint, paint);
2395
msarett16882062016-08-16 09:31:08 -07002396 if (nullptr == paint || paint->canComputeFastBounds()) {
2397 SkRect storage;
2398 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2399 return;
2400 }
2401 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002402 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002403
Ben Wagner2c312c42018-06-27 14:46:46 -04002404 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002405
2406 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002407 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002408 }
2409
2410 LOOPER_END
2411}
2412
2413void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2414 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002415 SkPaint realPaint;
2416 paint = init_image_paint(&realPaint, paint);
2417
msarett16882062016-08-16 09:31:08 -07002418 if (nullptr == paint || paint->canComputeFastBounds()) {
2419 SkRect storage;
2420 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2421 return;
2422 }
2423 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002424 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002425
Ben Wagner2c312c42018-06-27 14:46:46 -04002426 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002427
2428 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002429 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002430 }
2431
2432 LOOPER_END
2433}
2434
reed@google.come0d9ce82014-04-23 04:00:17 +00002435void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2436 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002437
Ben Wagner2c312c42018-06-27 14:46:46 -04002438 LOOPER_BEGIN(paint, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002439
2440 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002441 fScratchGlyphRunBuilder->drawText(
Herb Derby4a447432018-06-22 11:45:27 -04002442 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Herb Derby8a6348e2018-07-12 15:30:35 -04002443 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002444 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002445 }
2446
reed@google.com4e2b3d32011-04-07 14:18:59 +00002447 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002448}
2449
reed@google.come0d9ce82014-04-23 04:00:17 +00002450void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2451 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002452
Ben Wagner2c312c42018-06-27 14:46:46 -04002453 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002454
reed@android.com8a1c16f2008-12-17 15:59:43 +00002455 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002456 fScratchGlyphRunBuilder->drawPosText(looper.paint(), text, byteLength, pos);
Herb Derby8a6348e2018-07-12 15:30:35 -04002457 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002458 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002460
reed@google.com4e2b3d32011-04-07 14:18:59 +00002461 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002462}
2463
reed@google.come0d9ce82014-04-23 04:00:17 +00002464void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2465 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002466
Ben Wagner2c312c42018-06-27 14:46:46 -04002467 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002468
reed@android.com8a1c16f2008-12-17 15:59:43 +00002469 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002470 fScratchGlyphRunBuilder->drawPosTextH(
Herb Derby4a447432018-06-22 11:45:27 -04002471 looper.paint(), text, byteLength, xpos, constY);
Herb Derby8a6348e2018-07-12 15:30:35 -04002472 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002473 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002475
reed@google.com4e2b3d32011-04-07 14:18:59 +00002476 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002477}
2478
Herb Derby2eacff02018-07-18 13:41:15 -04002479void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[],
reed45561a02016-07-07 12:47:17 -07002480 const SkRect* cullRect, const SkPaint& paint) {
2481 if (cullRect && this->quickReject(*cullRect)) {
2482 return;
2483 }
2484
Ben Wagner2c312c42018-06-27 14:46:46 -04002485 LOOPER_BEGIN(paint, nullptr)
reed45561a02016-07-07 12:47:17 -07002486
2487 while (iter.next()) {
Herb Derby2eacff02018-07-18 13:41:15 -04002488 fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len);
2489 auto list = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb935cf82018-07-26 16:54:18 -04002490 if (!list.empty()) {
2491 auto glyphRun = list[0];
Herb Derby2eacff02018-07-18 13:41:15 -04002492 iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform);
2493 }
reed45561a02016-07-07 12:47:17 -07002494 }
2495
2496 LOOPER_END
2497}
2498
fmalita00d5c2c2014-08-21 08:53:26 -07002499void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2500 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002501 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002502 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002503 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002504 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002505 SkRect tmp;
2506 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2507 return;
2508 }
2509 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002510 }
2511
fmalita024f9962015-03-03 19:08:17 -08002512 // We cannot filter in the looper as we normally do, because the paint is
2513 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002514 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002515
fmalitaaa1b9122014-08-28 14:32:24 -07002516 while (iter.next()) {
Herb Derbyb983e6b2018-07-13 13:26:29 -04002517 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, SkPoint::Make(x, y));
2518 iter.fDevice->drawGlyphRunList(fScratchGlyphRunBuilder->useGlyphRunList());
fmalita00d5c2c2014-08-21 08:53:26 -07002519 }
2520
fmalitaaa1b9122014-08-28 14:32:24 -07002521 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002522}
2523
Cary Clark2a475ea2017-04-28 15:35:12 -04002524void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2525 this->drawText(string.c_str(), string.size(), x, y, paint);
2526}
2527
reed@google.come0d9ce82014-04-23 04:00:17 +00002528// These will become non-virtual, so they always call the (virtual) onDraw... method
2529void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2530 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002531 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002532 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002533 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002534 this->onDrawText(text, byteLength, x, y, paint);
2535 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002536}
2537void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2538 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002539 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002540 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002541 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002542 this->onDrawPosText(text, byteLength, pos, paint);
2543 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002544}
2545void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2546 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002547 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002548 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002549 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002550 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2551 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002552}
Mike Reed7c8d2e92018-08-27 16:38:05 -04002553
reed45561a02016-07-07 12:47:17 -07002554void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2555 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002556 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002557 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002558 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002559 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2560 }
2561}
fmalita00d5c2c2014-08-21 08:53:26 -07002562void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2563 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002564 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002565 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002566 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002567 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002568}
reed@google.come0d9ce82014-04-23 04:00:17 +00002569
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002570void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002571 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002572 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002573
2574 while (iter.next()) {
2575 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002576 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002577 }
2578
2579 LOOPER_END
2580}
2581
dandovb3c9d1c2014-08-12 08:34:29 -07002582void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002583 const SkPoint texCoords[4], SkBlendMode bmode,
2584 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002585 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002586 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002587 return;
2588 }
mtklein6cfa73a2014-08-13 13:33:49 -07002589
Mike Reedfaba3712016-11-03 14:45:31 -04002590 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002591}
2592
2593void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002594 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002595 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002596 // Since a patch is always within the convex hull of the control points, we discard it when its
2597 // bounding rectangle is completely outside the current clip.
2598 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002599 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002600 if (this->quickReject(bounds)) {
2601 return;
2602 }
mtklein6cfa73a2014-08-13 13:33:49 -07002603
Ben Wagner2c312c42018-06-27 14:46:46 -04002604 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002605
dandovecfff212014-08-04 10:02:00 -07002606 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002607 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002608 }
mtklein6cfa73a2014-08-13 13:33:49 -07002609
dandovecfff212014-08-04 10:02:00 -07002610 LOOPER_END
2611}
2612
reeda8db7282015-07-07 10:22:31 -07002613void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002614#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002615 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002616#endif
reede3b38ce2016-01-08 09:18:44 -08002617 RETURN_ON_NULL(dr);
2618 if (x || y) {
2619 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2620 this->onDrawDrawable(dr, &matrix);
2621 } else {
2622 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002623 }
2624}
2625
reeda8db7282015-07-07 10:22:31 -07002626void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002627#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002628 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002629#endif
reede3b38ce2016-01-08 09:18:44 -08002630 RETURN_ON_NULL(dr);
2631 if (matrix && matrix->isIdentity()) {
2632 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002633 }
reede3b38ce2016-01-08 09:18:44 -08002634 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002635}
2636
2637void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002638 // drawable bounds are no longer reliable (e.g. android displaylist)
2639 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002640 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002641}
2642
reed71c3c762015-06-24 10:29:17 -07002643void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002644 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002645 const SkRect* cull, const SkPaint* paint) {
2646 if (cull && this->quickReject(*cull)) {
2647 return;
2648 }
2649
2650 SkPaint pnt;
2651 if (paint) {
2652 pnt = *paint;
2653 }
halcanary9d524f22016-03-29 09:03:52 -07002654
Ben Wagner2c312c42018-06-27 14:46:46 -04002655 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002656 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002657 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002658 }
2659 LOOPER_END
2660}
2661
reedf70b5312016-03-04 16:36:20 -08002662void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2663 SkASSERT(key);
2664
2665 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002666 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002667 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002668 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002669 }
2670 LOOPER_END
2671}
2672
reed@android.com8a1c16f2008-12-17 15:59:43 +00002673//////////////////////////////////////////////////////////////////////////////
2674// These methods are NOT virtual, and therefore must call back into virtual
2675// methods, rather than actually drawing themselves.
2676//////////////////////////////////////////////////////////////////////////////
2677
reed374772b2016-10-05 17:33:02 -07002678void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002679 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002680 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002681 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002682 this->drawPaint(paint);
2683}
2684
2685void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002686 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002687 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2688}
2689
Mike Reed3661bc92017-02-22 13:21:42 -05002690void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002691 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002692 pts[0].set(x0, y0);
2693 pts[1].set(x1, y1);
2694 this->drawPoints(kLines_PointMode, 2, pts, paint);
2695}
2696
Mike Reed3661bc92017-02-22 13:21:42 -05002697void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698 if (radius < 0) {
2699 radius = 0;
2700 }
2701
2702 SkRect r;
2703 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002704 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002705}
2706
2707void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2708 const SkPaint& paint) {
2709 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002710 SkRRect rrect;
2711 rrect.setRectXY(r, rx, ry);
2712 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002713 } else {
2714 this->drawRect(r, paint);
2715 }
2716}
2717
reed@android.com8a1c16f2008-12-17 15:59:43 +00002718void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2719 SkScalar sweepAngle, bool useCenter,
2720 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002721 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002722 if (oval.isEmpty() || !sweepAngle) {
2723 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002724 }
bsalomon21af9ca2016-08-25 12:29:23 -07002725 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726}
2727
reed@android.comf76bacf2009-05-13 14:00:33 +00002728///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002729
Mike Klein88d90712018-01-27 17:30:04 +00002730/**
2731 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2732 * against the playback cost of recursing into the subpicture to get at its actual ops.
2733 *
2734 * For now we pick a conservatively small value, though measurement (and other heuristics like
2735 * the type of ops contained) may justify changing this value.
2736 */
2737#define kMaxPictureOpsToUnrollInsteadOfRef 1
2738
reedd5fa1a42014-08-09 11:08:05 -07002739void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002740 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002741 RETURN_ON_NULL(picture);
2742
reede3b38ce2016-01-08 09:18:44 -08002743 if (matrix && matrix->isIdentity()) {
2744 matrix = nullptr;
2745 }
Mike Klein88d90712018-01-27 17:30:04 +00002746 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2747 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2748 picture->playback(this);
2749 } else {
2750 this->onDrawPicture(picture, matrix, paint);
2751 }
reedd5fa1a42014-08-09 11:08:05 -07002752}
robertphillips9b14f262014-06-04 05:40:44 -07002753
reedd5fa1a42014-08-09 11:08:05 -07002754void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2755 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002756 if (!paint || paint->canComputeFastBounds()) {
2757 SkRect bounds = picture->cullRect();
2758 if (paint) {
2759 paint->computeFastBounds(bounds, &bounds);
2760 }
2761 if (matrix) {
2762 matrix->mapRect(&bounds);
2763 }
2764 if (this->quickReject(bounds)) {
2765 return;
2766 }
2767 }
2768
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002769 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002770 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002771}
2772
reed@android.com8a1c16f2008-12-17 15:59:43 +00002773///////////////////////////////////////////////////////////////////////////////
2774///////////////////////////////////////////////////////////////////////////////
2775
reed3aafe112016-08-18 12:45:34 -07002776SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002777 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778
2779 SkASSERT(canvas);
2780
reed3aafe112016-08-18 12:45:34 -07002781 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782 fDone = !fImpl->next();
2783}
2784
2785SkCanvas::LayerIter::~LayerIter() {
2786 fImpl->~SkDrawIter();
2787}
2788
2789void SkCanvas::LayerIter::next() {
2790 fDone = !fImpl->next();
2791}
2792
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002793SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002794 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795}
2796
2797const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002798 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799}
2800
2801const SkPaint& SkCanvas::LayerIter::paint() const {
2802 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002803 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002804 paint = &fDefaultPaint;
2805 }
2806 return *paint;
2807}
2808
Mike Reedca37f322018-03-08 13:22:16 -05002809SkIRect SkCanvas::LayerIter::clipBounds() const {
2810 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002811}
2812
reed@android.com8a1c16f2008-12-17 15:59:43 +00002813int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2814int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002815
2816///////////////////////////////////////////////////////////////////////////////
2817
Brian Osman10fc6fd2018-03-02 11:01:10 -05002818// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002819static bool supported_for_raster_canvas(const SkImageInfo& info) {
2820 switch (info.alphaType()) {
2821 case kPremul_SkAlphaType:
2822 case kOpaque_SkAlphaType:
2823 break;
2824 default:
2825 return false;
2826 }
2827
2828 switch (info.colorType()) {
2829 case kAlpha_8_SkColorType:
2830 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002831 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002832 case kRGBA_F16_SkColorType:
Mike Klein37854712018-06-26 11:43:06 -04002833 case kRGBA_F32_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002834 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002835 break;
2836 default:
2837 return false;
2838 }
2839
2840 return true;
2841}
2842
Mike Reed5df49342016-11-12 08:06:55 -06002843std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002844 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002845 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002846 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002847 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002848
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002849 SkBitmap bitmap;
2850 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002851 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002852 }
Mike Reed12f77342017-11-08 11:19:52 -05002853
2854 return props ?
2855 skstd::make_unique<SkCanvas>(bitmap, *props) :
2856 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002857}
reedd5fa1a42014-08-09 11:08:05 -07002858
2859///////////////////////////////////////////////////////////////////////////////
2860
Florin Malitaee424ac2016-12-01 12:47:59 -05002861SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2862 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2863
Florin Malita439ace92016-12-02 12:05:41 -05002864SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2865 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2866
Herb Derbyefe39bc2018-05-01 17:06:20 -04002867SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002868 : INHERITED(device) {}
2869
Florin Malitaee424ac2016-12-01 12:47:59 -05002870SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2871 (void)this->INHERITED::getSaveLayerStrategy(rec);
2872 return kNoLayer_SaveLayerStrategy;
2873}
2874
2875///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002876
reed73603f32016-09-20 08:42:38 -07002877static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2878static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2879static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2880static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2881static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2882static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002883
2884///////////////////////////////////////////////////////////////////////////////////////////////////
2885
2886SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2887 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002888 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002889 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2890 SkIPoint origin = dev->getOrigin();
2891 SkMatrix ctm = this->getTotalMatrix();
2892 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2893
2894 SkIRect clip = fMCRec->fRasterClip.getBounds();
2895 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002896 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002897 clip.setEmpty();
2898 }
2899
2900 fAllocator->updateHandle(handle, ctm, clip);
2901 return handle;
2902 }
2903 return nullptr;
2904}
2905
2906static bool install(SkBitmap* bm, const SkImageInfo& info,
2907 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002908 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002909}
2910
2911SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2912 SkBitmap* bm) {
2913 SkRasterHandleAllocator::Rec rec;
2914 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2915 return nullptr;
2916 }
2917 return rec.fHandle;
2918}
2919
2920std::unique_ptr<SkCanvas>
2921SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2922 const SkImageInfo& info, const Rec* rec) {
2923 if (!alloc || !supported_for_raster_canvas(info)) {
2924 return nullptr;
2925 }
2926
2927 SkBitmap bm;
2928 Handle hndl;
2929
2930 if (rec) {
2931 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2932 } else {
2933 hndl = alloc->allocBitmap(info, &bm);
2934 }
2935 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2936}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002937
2938///////////////////////////////////////////////////////////////////////////////////////////////////
2939
2940