blob: ad9bcf5132f3ea27ed6084e32bcad0454414c92d [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050026#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070027#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070028#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070029#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000030#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000031#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050032#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000033#include "SkRRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080034#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040035#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000036#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070037#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000038#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000039#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080040#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070041#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000042
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000043#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080044#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#include "GrRenderTarget.h"
Brian Osman3b655982017-03-07 16:58:08 -050046#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070047
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050049#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050050#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051
reede3b38ce2016-01-08 09:18:44 -080052#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
53
Mike Reed139e5e02017-03-08 11:29:33 -050054class SkNoPixelsDevice : public SkBaseDevice {
55public:
56 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
57 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
Mike Reed566e53c2017-03-10 10:49:45 -050058 {
Mike Reede393a622017-03-10 16:35:25 -050059 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
60 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050061 }
Mike Reed139e5e02017-03-08 11:29:33 -050062
63 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050064 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050065 this->privateResize(bounds.width(), bounds.height());
66 }
67
68protected:
69 // We don't track the clip at all (for performance), but we have to respond to some queries.
70 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
71 void onSave() override {}
72 void onRestore() override {}
73 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
74 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
75 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
76 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
77 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
78 bool onClipIsAA() const override { return false; }
79 void onAsRgnClip(SkRegion* rgn) const override {
80 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
81 }
82 ClipType onGetClipType() const override {
83 return kRect_ClipType;
84 }
85
86 void drawPaint(const SkPaint& paint) override {}
87 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
88 void drawRect(const SkRect&, const SkPaint&) override {}
89 void drawOval(const SkRect&, const SkPaint&) override {}
90 void drawRRect(const SkRRect&, const SkPaint&) override {}
91 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
92 void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {}
93 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
94 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
95 SkCanvas::SrcRectConstraint) override {}
96 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
97 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
98 const SkPaint&) override {}
99 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
Mike Reed2f6b5a42017-03-19 15:04:17 -0400100 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -0500101
102private:
103 typedef SkBaseDevice INHERITED;
104};
105
106///////////////////////////////////////////////////////////////////////////////////////////////////
107
reedc83a2972015-07-16 07:40:45 -0700108/*
109 * Return true if the drawing this rect would hit every pixels in the canvas.
110 *
111 * Returns false if
112 * - rect does not contain the canvas' bounds
113 * - paint is not fill
114 * - paint would blur or otherwise change the coverage of the rect
115 */
116bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
117 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700118 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
119 (int)kNone_ShaderOverrideOpacity,
120 "need_matching_enums0");
121 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
122 (int)kOpaque_ShaderOverrideOpacity,
123 "need_matching_enums1");
124 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
125 (int)kNotOpaque_ShaderOverrideOpacity,
126 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700127
128 const SkISize size = this->getBaseLayerSize();
129 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500130
131 // if we're clipped at all, we can't overwrite the entire surface
132 {
133 SkBaseDevice* base = this->getDevice();
134 SkBaseDevice* top = this->getTopDevice();
135 if (base != top) {
136 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
137 }
138 if (!base->clipIsWideOpen()) {
139 return false;
140 }
reedc83a2972015-07-16 07:40:45 -0700141 }
142
143 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700144 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700145 return false; // conservative
146 }
halcanaryc5769b22016-08-10 07:13:21 -0700147
148 SkRect devRect;
149 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
150 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700151 return false;
152 }
153 }
154
155 if (paint) {
156 SkPaint::Style paintStyle = paint->getStyle();
157 if (!(paintStyle == SkPaint::kFill_Style ||
158 paintStyle == SkPaint::kStrokeAndFill_Style)) {
159 return false;
160 }
161 if (paint->getMaskFilter() || paint->getLooper()
162 || paint->getPathEffect() || paint->getImageFilter()) {
163 return false; // conservative
164 }
165 }
166 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
167}
168
169///////////////////////////////////////////////////////////////////////////////////////////////////
170
reedd990e2f2014-12-22 11:58:30 -0800171static bool gIgnoreSaveLayerBounds;
172void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
173 gIgnoreSaveLayerBounds = ignore;
174}
175bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
176 return gIgnoreSaveLayerBounds;
177}
178
reed0acf1b42014-12-22 16:12:38 -0800179static bool gTreatSpriteAsBitmap;
180void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
181 gTreatSpriteAsBitmap = spriteAsBitmap;
182}
183bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
184 return gTreatSpriteAsBitmap;
185}
186
reed@google.comda17f752012-08-16 18:27:05 +0000187// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188//#define SK_TRACE_SAVERESTORE
189
190#ifdef SK_TRACE_SAVERESTORE
191 static int gLayerCounter;
192 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
193 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
194
195 static int gRecCounter;
196 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
197 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
198
199 static int gCanvasCounter;
200 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
201 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
202#else
203 #define inc_layer()
204 #define dec_layer()
205 #define inc_rec()
206 #define dec_rec()
207 #define inc_canvas()
208 #define dec_canvas()
209#endif
210
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000211typedef SkTLazy<SkPaint> SkLazyPaint;
212
reedc83a2972015-07-16 07:40:45 -0700213void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000214 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700215 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
216 ? SkSurface::kDiscard_ContentChangeMode
217 : SkSurface::kRetain_ContentChangeMode);
218 }
219}
220
221void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
222 ShaderOverrideOpacity overrideOpacity) {
223 if (fSurfaceBase) {
224 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
225 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
226 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
227 // and therefore we don't care which mode we're in.
228 //
229 if (fSurfaceBase->outstandingImageSnapshot()) {
230 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
231 mode = SkSurface::kDiscard_ContentChangeMode;
232 }
233 }
234 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000235 }
236}
237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000240/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 The clip/matrix/proc are fields that reflect the top of the save/restore
242 stack. Whenever the canvas changes, it marks a dirty flag, and then before
243 these are used (assuming we're not on a layer) we rebuild these cache
244 values: they reflect the top of the save stack, but translated and clipped
245 by the device's XY offset and bitmap-bounds.
246*/
247struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400248 DeviceCM* fNext;
249 sk_sp<SkBaseDevice> fDevice;
250 SkRasterClip fClip;
251 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
252 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400253 sk_sp<SkImage> fClipImage;
254 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255
Florin Malita53f77bd2017-04-28 13:48:37 -0400256 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000257 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700258 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400259 , fDevice(std::move(device))
260 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700261 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000262 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400263 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400264 {}
reed@google.com4b226022011-01-11 18:32:13 +0000265
mtkleinfeaadee2015-04-08 11:25:48 -0700266 void reset(const SkIRect& bounds) {
267 SkASSERT(!fPaint);
268 SkASSERT(!fNext);
269 SkASSERT(fDevice);
270 fClip.setRect(bounds);
271 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272};
273
274/* This is the record we keep for each save/restore level in the stack.
275 Since a level optionally copies the matrix and/or stack, we have pointers
276 for these fields. If the value is copied for this level, the copy is
277 stored in the ...Storage field, and the pointer points to that. If the
278 value is not copied for this level, we ignore ...Storage, and just point
279 at the corresponding value in the previous level in the stack.
280*/
281class SkCanvas::MCRec {
282public:
reed1f836ee2014-07-07 07:49:34 -0700283 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700284 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 /* If there are any layers in the stack, this points to the top-most
286 one that is at or below this level in the stack (so we know what
287 bitmap/device to draw into from this level. This value is NOT
288 reference counted, since the real owner is either our fLayer field,
289 or a previous one in a lower level.)
290 */
Mike Reeda1361362017-03-07 09:37:29 -0500291 DeviceCM* fTopLayer;
292 SkConservativeClip fRasterClip;
293 SkMatrix fMatrix;
294 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295
vjiaoblacke5de1302016-07-13 14:05:28 -0700296 // This is the current cumulative depth (aggregate of all done translateZ calls)
297 SkScalar fCurDrawDepth;
298
Mike Reeda1361362017-03-07 09:37:29 -0500299 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700300 fFilter = nullptr;
301 fLayer = nullptr;
302 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800303 fMatrix.reset();
304 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700305 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700306
reedd9544982014-09-09 18:46:22 -0700307 // don't bother initializing fNext
308 inc_rec();
309 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700310 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
311 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700312 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700313 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700314 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800315 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700316
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317 // don't bother initializing fNext
318 inc_rec();
319 }
320 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000321 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700322 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323 dec_rec();
324 }
mtkleinfeaadee2015-04-08 11:25:48 -0700325
326 void reset(const SkIRect& bounds) {
327 SkASSERT(fLayer);
328 SkASSERT(fDeferredSaveCount == 0);
329
330 fMatrix.reset();
331 fRasterClip.setRect(bounds);
332 fLayer->reset(bounds);
333 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334};
335
Mike Reeda1361362017-03-07 09:37:29 -0500336class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337public:
Mike Reeda1361362017-03-07 09:37:29 -0500338 SkDrawIter(SkCanvas* canvas)
339 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
340 {}
reed@google.com4b226022011-01-11 18:32:13 +0000341
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000343 const DeviceCM* rec = fCurrLayer;
344 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400345 fDevice = rec->fDevice.get();
346 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700348 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 return true;
350 }
351 return false;
352 }
reed@google.com4b226022011-01-11 18:32:13 +0000353
reed@google.com6f8f2922011-03-04 22:27:10 +0000354 int getX() const { return fDevice->getOrigin().x(); }
355 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000357
Mike Reed99330ba2017-02-22 11:01:08 -0500358 SkBaseDevice* fDevice;
359
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 const DeviceCM* fCurrLayer;
362 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363};
364
Florin Malita713b8ef2017-04-28 10:57:24 -0400365#define FOR_EACH_TOP_DEVICE( code ) \
366 do { \
367 DeviceCM* layer = fMCRec->fTopLayer; \
368 while (layer) { \
369 SkBaseDevice* device = layer->fDevice.get(); \
370 if (device) { \
371 code; \
372 } \
373 layer = layer->fNext; \
374 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500375 } while (0)
376
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377/////////////////////////////////////////////////////////////////////////////
378
reeddbc3cef2015-04-29 12:18:57 -0700379static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
380 return lazy->isValid() ? lazy->get() : lazy->set(orig);
381}
382
383/**
384 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700385 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700386 */
reedd053ce92016-03-22 10:17:23 -0700387static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700388 SkImageFilter* imgf = paint.getImageFilter();
389 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700390 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700391 }
392
reedd053ce92016-03-22 10:17:23 -0700393 SkColorFilter* imgCFPtr;
394 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700395 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700396 }
reedd053ce92016-03-22 10:17:23 -0700397 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700398
399 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700400 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700401 // there is no existing paint colorfilter, so we can just return the imagefilter's
402 return imgCF;
403 }
404
405 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
406 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700407 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700408}
409
senorblanco87e066e2015-10-28 11:23:36 -0700410/**
411 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
412 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
413 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
414 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
415 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
416 * conservative "effective" bounds based on the settings in the paint... with one exception. This
417 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
418 * deliberately ignored.
419 */
420static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
421 const SkRect& rawBounds,
422 SkRect* storage) {
423 SkPaint tmpUnfiltered(paint);
424 tmpUnfiltered.setImageFilter(nullptr);
425 if (tmpUnfiltered.canComputeFastBounds()) {
426 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
427 } else {
428 return rawBounds;
429 }
430}
431
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432class AutoDrawLooper {
433public:
senorblanco87e066e2015-10-28 11:23:36 -0700434 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
435 // paint. It's used to determine the size of the offscreen layer for filters.
436 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700437 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700438 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000439 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800440#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800442#else
443 fFilter = nullptr;
444#endif
reed4a8126e2014-09-22 07:29:03 -0700445 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000446 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700447 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000448 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449
reedd053ce92016-03-22 10:17:23 -0700450 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700451 if (simplifiedCF) {
452 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700453 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700454 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700455 fPaint = paint;
456 }
457
458 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700459 /**
460 * We implement ImageFilters for a given draw by creating a layer, then applying the
461 * imagefilter to the pixels of that layer (its backing surface/image), and then
462 * we call restore() to xfer that layer to the main canvas.
463 *
464 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
465 * 2. Generate the src pixels:
466 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
467 * return (fPaint). We then draw the primitive (using srcover) into a cleared
468 * buffer/surface.
469 * 3. Restore the layer created in #1
470 * The imagefilter is passed the buffer/surface from the layer (now filled with the
471 * src pixels of the primitive). It returns a new "filtered" buffer, which we
472 * draw onto the previous layer using the xfermode from the original paint.
473 */
reed@google.com8926b162012-03-23 15:36:36 +0000474 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500475 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700476 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700477 SkRect storage;
478 if (rawBounds) {
479 // Make rawBounds include all paint outsets except for those due to image filters.
480 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
481 }
reedbfd5f172016-01-07 11:28:08 -0800482 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700483 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700484 fTempLayerForImageFilter = true;
485 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000486 }
487
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000488 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500489 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000490 fIsSimple = false;
491 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700492 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000493 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700494 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000495 }
496 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000497
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700499 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000500 fCanvas->internalRestore();
501 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000502 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000504
reed@google.com4e2b3d32011-04-07 14:18:59 +0000505 const SkPaint& paint() const {
506 SkASSERT(fPaint);
507 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000508 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000509
reed@google.com129ec222012-05-15 13:24:09 +0000510 bool next(SkDrawFilter::Type drawType) {
511 if (fDone) {
512 return false;
513 } else if (fIsSimple) {
514 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000515 return !fPaint->nothingToDraw();
516 } else {
517 return this->doNext(drawType);
518 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000519 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000520
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500522 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700523 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000524 SkCanvas* fCanvas;
525 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000526 SkDrawFilter* fFilter;
527 const SkPaint* fPaint;
528 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700529 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000530 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000531 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000532 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500533 char fStorage[48];
534 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000535
536 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537};
538
reed@google.com129ec222012-05-15 13:24:09 +0000539bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700540 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000541 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700542 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000543
reeddbc3cef2015-04-29 12:18:57 -0700544 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
545 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000546
reed5c476fb2015-04-20 08:04:21 -0700547 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700548 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700549 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000550 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000551
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000552 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000553 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000554 return false;
555 }
556 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000557 if (!fFilter->filter(paint, drawType)) {
558 fDone = true;
559 return false;
560 }
halcanary96fcdcc2015-08-27 07:41:13 -0700561 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000562 // no looper means we only draw once
563 fDone = true;
564 }
565 }
566 fPaint = paint;
567
568 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000569 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000570 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000571 }
572
573 // call this after any possible paint modifiers
574 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700575 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000576 return false;
577 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000578 return true;
579}
580
reed@android.com8a1c16f2008-12-17 15:59:43 +0000581////////// macros to place around the internal draw calls //////////////////
582
reed3aafe112016-08-18 12:45:34 -0700583#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
584 this->predrawNotify(); \
585 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
586 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800587 SkDrawIter iter(this);
588
589
reed@google.com8926b162012-03-23 15:36:36 +0000590#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000591 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700592 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000593 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000594 SkDrawIter iter(this);
595
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000596#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000597 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700598 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000599 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000601
reedc83a2972015-07-16 07:40:45 -0700602#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
603 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700604 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700605 while (looper.next(type)) { \
606 SkDrawIter iter(this);
607
reed@google.com4e2b3d32011-04-07 14:18:59 +0000608#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000609
610////////////////////////////////////////////////////////////////////////////
611
msarettfbfa2582016-08-12 08:29:08 -0700612static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
613 if (bounds.isEmpty()) {
614 return SkRect::MakeEmpty();
615 }
616
617 // Expand bounds out by 1 in case we are anti-aliasing. We store the
618 // bounds as floats to enable a faster quick reject implementation.
619 SkRect dst;
620 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
621 return dst;
622}
623
mtkleinfeaadee2015-04-08 11:25:48 -0700624void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
625 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700626 fMCRec->reset(bounds);
627
628 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500629 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400630 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700631 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700632 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700633}
634
reedd9544982014-09-09 18:46:22 -0700635SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800636 if (device && device->forceConservativeRasterClip()) {
637 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
638 }
reed42b73eb2015-11-20 13:42:42 -0800639
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000640 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800641 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700642 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700643#ifdef SK_EXPERIMENTAL_SHADOWING
644 fLights = nullptr;
645#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646
647 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500648 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500649 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700650 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000651
reeda499f902015-05-01 09:34:31 -0700652 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
653 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400654 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700655
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657
halcanary96fcdcc2015-08-27 07:41:13 -0700658 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000659
reedf92c8662014-08-18 08:02:43 -0700660 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700661 // The root device and the canvas should always have the same pixel geometry
662 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800663 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700664 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500665
Mike Reedc42a1cd2017-02-14 14:25:14 -0500666 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700667 }
msarettfbfa2582016-08-12 08:29:08 -0700668
reedf92c8662014-08-18 08:02:43 -0700669 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670}
671
reed@google.comcde92112011-07-06 20:00:52 +0000672SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000673 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700674 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000675{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000676 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000677
halcanary96fcdcc2015-08-27 07:41:13 -0700678 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000679}
680
reed96a857e2015-01-25 10:33:58 -0800681SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000682 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800683 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000684{
685 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700686
Mike Reed566e53c2017-03-10 10:49:45 -0500687 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700688 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700689}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000690
reed78e27682014-11-19 08:04:34 -0800691SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700692 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700693 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700694{
695 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700696
Mike Reed566e53c2017-03-10 10:49:45 -0500697 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
698 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700699}
700
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000701SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000702 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700703 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000704{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000705 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700706
reedd9544982014-09-09 18:46:22 -0700707 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000708}
709
robertphillipsfcf78292015-06-19 11:49:52 -0700710SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
711 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700712 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700713{
714 inc_canvas();
715
716 this->init(device, flags);
717}
718
reed4a8126e2014-09-22 07:29:03 -0700719SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700720 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700721 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700722{
723 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700724
Hal Canary704cd322016-11-07 14:13:52 -0500725 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
726 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700727}
reed29c857d2014-09-21 10:25:07 -0700728
Mike Reed356f7c22017-01-10 11:58:39 -0500729SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
730 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700731 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
732 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500733 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700734{
735 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700736
Mike Reed356f7c22017-01-10 11:58:39 -0500737 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500738 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000739}
740
Mike Reed356f7c22017-01-10 11:58:39 -0500741SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
742
Matt Sarett31f99ce2017-04-11 08:46:01 -0400743#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
744SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
745 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
746 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
747 , fAllocator(nullptr)
748{
749 inc_canvas();
750
751 SkBitmap tmp(bitmap);
752 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
753 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
754 this->init(device.get(), kDefault_InitFlags);
755}
756#endif
757
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758SkCanvas::~SkCanvas() {
759 // free up the contents of our deque
760 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000761
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762 this->internalRestore(); // restore the last, since we're going away
763
halcanary385fe4d2015-08-26 13:07:48 -0700764 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000765
reed@android.com8a1c16f2008-12-17 15:59:43 +0000766 dec_canvas();
767}
768
fmalita53d9f1c2016-01-25 06:23:54 -0800769#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000770SkDrawFilter* SkCanvas::getDrawFilter() const {
771 return fMCRec->fFilter;
772}
773
774SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700775 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000776 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
777 return filter;
778}
fmalita77650002016-01-21 18:47:11 -0800779#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000780
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000781SkMetaData& SkCanvas::getMetaData() {
782 // metadata users are rare, so we lazily allocate it. If that changes we
783 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700784 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000785 fMetaData = new SkMetaData;
786 }
787 return *fMetaData;
788}
789
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790///////////////////////////////////////////////////////////////////////////////
791
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000792void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700793 this->onFlush();
794}
795
796void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000797 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000798 if (device) {
799 device->flush();
800 }
801}
802
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000803SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000804 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000805 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
806}
807
senorblancoafc7cce2016-02-02 18:44:15 -0800808SkIRect SkCanvas::getTopLayerBounds() const {
809 SkBaseDevice* d = this->getTopDevice();
810 if (!d) {
811 return SkIRect::MakeEmpty();
812 }
813 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
814}
815
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000816SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000818 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400820 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821}
822
Florin Malita0ed3b642017-01-13 16:56:38 +0000823SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400824 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000825}
826
reed96472de2014-12-10 09:53:42 -0800827bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000828 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000829 if (!device) {
830 return false;
831 }
mtkleinf0f14112014-12-12 08:46:25 -0800832
Matt Sarett03dd6d52017-01-23 12:15:09 -0500833 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000834}
835
Mike Reed12e946b2017-04-17 10:53:29 -0400836bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
837 return pm.addr() && this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y);
838}
839
840bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
841 SkPixmap pm;
842 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
843}
844
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000845bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400846 SkPixmap pm;
847 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700848 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000849 }
850 return false;
851}
852
Matt Sarett03dd6d52017-01-23 12:15:09 -0500853bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000854 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000855 SkBaseDevice* device = this->getDevice();
856 if (!device) {
857 return false;
858 }
859
Matt Sarett03dd6d52017-01-23 12:15:09 -0500860 // This check gives us an early out and prevents generation ID churn on the surface.
861 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
862 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
863 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
864 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000865 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000866
Matt Sarett03dd6d52017-01-23 12:15:09 -0500867 // Tell our owning surface to bump its generation ID.
868 const bool completeOverwrite =
869 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700870 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700871
Matt Sarett03dd6d52017-01-23 12:15:09 -0500872 // This can still fail, most notably in the case of a invalid color type or alpha type
873 // conversion. We could pull those checks into this function and avoid the unnecessary
874 // generation ID bump. But then we would be performing those checks twice, since they
875 // are also necessary at the bitmap/pixmap entry points.
876 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000877}
reed@google.com51df9e32010-12-23 19:29:18 +0000878
reed@android.com8a1c16f2008-12-17 15:59:43 +0000879//////////////////////////////////////////////////////////////////////////////
880
reed2ff1fce2014-12-11 07:07:37 -0800881void SkCanvas::checkForDeferredSave() {
882 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800883 this->doSave();
884 }
885}
886
reedf0090cb2014-11-26 08:55:51 -0800887int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800888#ifdef SK_DEBUG
889 int count = 0;
890 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
891 for (;;) {
892 const MCRec* rec = (const MCRec*)iter.next();
893 if (!rec) {
894 break;
895 }
896 count += 1 + rec->fDeferredSaveCount;
897 }
898 SkASSERT(count == fSaveCount);
899#endif
900 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800901}
902
903int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800904 fSaveCount += 1;
905 fMCRec->fDeferredSaveCount += 1;
906 return this->getSaveCount() - 1; // return our prev value
907}
908
909void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800910 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700911
912 SkASSERT(fMCRec->fDeferredSaveCount > 0);
913 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800914 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800915}
916
917void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800918 if (fMCRec->fDeferredSaveCount > 0) {
919 SkASSERT(fSaveCount > 1);
920 fSaveCount -= 1;
921 fMCRec->fDeferredSaveCount -= 1;
922 } else {
923 // check for underflow
924 if (fMCStack.count() > 1) {
925 this->willRestore();
926 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700927 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800928 this->internalRestore();
929 this->didRestore();
930 }
reedf0090cb2014-11-26 08:55:51 -0800931 }
932}
933
934void SkCanvas::restoreToCount(int count) {
935 // sanity check
936 if (count < 1) {
937 count = 1;
938 }
mtkleinf0f14112014-12-12 08:46:25 -0800939
reedf0090cb2014-11-26 08:55:51 -0800940 int n = this->getSaveCount() - count;
941 for (int i = 0; i < n; ++i) {
942 this->restore();
943 }
944}
945
reed2ff1fce2014-12-11 07:07:37 -0800946void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000947 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700948 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000950
Mike Reedc42a1cd2017-02-14 14:25:14 -0500951 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952}
953
reed4960eee2015-12-18 07:09:18 -0800954bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800955 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956}
957
reed4960eee2015-12-18 07:09:18 -0800958bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700959 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500960 SkIRect clipBounds = this->getDeviceClipBounds();
961 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000962 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000963 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000964
reed96e657d2015-03-10 17:30:07 -0700965 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
966
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000967 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700968 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800969 if (bounds && !imageFilter->canComputeFastBounds()) {
970 bounds = nullptr;
971 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000972 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000973 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700974 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000975 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000976
reed96e657d2015-03-10 17:30:07 -0700977 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 r.roundOut(&ir);
979 // early exit if the layer's bounds are clipped out
980 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800981 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500982 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700983 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700984 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000985 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000986 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987 }
988 } else { // no user bounds, so just use the clip
989 ir = clipBounds;
990 }
reed180aec42015-03-11 10:39:04 -0700991 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000992
reed4960eee2015-12-18 07:09:18 -0800993 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700994 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700995 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700996 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000997 }
998
999 if (intersection) {
1000 *intersection = ir;
1001 }
1002 return true;
1003}
1004
reed4960eee2015-12-18 07:09:18 -08001005
reed4960eee2015-12-18 07:09:18 -08001006int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1007 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001008}
1009
reed70ee31b2015-12-10 13:44:45 -08001010int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001011 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1012}
1013
1014int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001015 SkTCopyOnFirstWrite<SaveLayerRec> rec(origRec);
reed4960eee2015-12-18 07:09:18 -08001016 if (gIgnoreSaveLayerBounds) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001017 rec.writable()->fBounds = nullptr;
reed4960eee2015-12-18 07:09:18 -08001018 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001019
1020 SaveLayerStrategy strategy = this->getSaveLayerStrategy(*rec);
reed4960eee2015-12-18 07:09:18 -08001021 fSaveCount += 1;
Florin Malita53f77bd2017-04-28 13:48:37 -04001022 this->internalSaveLayer(*rec, strategy);
reed4960eee2015-12-18 07:09:18 -08001023 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001024}
1025
reeda2217ef2016-07-20 06:04:34 -07001026void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001027 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001028 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001029 SkDraw draw;
1030 SkRasterClip rc;
1031 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1032 if (!dst->accessPixels(&draw.fDst)) {
1033 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001034 }
reeda2217ef2016-07-20 06:04:34 -07001035 draw.fMatrix = &SkMatrix::I();
1036 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001037
1038 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001039 if (filter) {
1040 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1041 }
reeda2217ef2016-07-20 06:04:34 -07001042
Mike Reedc42a1cd2017-02-14 14:25:14 -05001043 int x = src->getOrigin().x() - dstOrigin.x();
1044 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001045 auto special = src->snapSpecial();
1046 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001047 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -07001048 }
robertphillips7354a4b2015-12-16 05:08:27 -08001049}
reed70ee31b2015-12-10 13:44:45 -08001050
reed129ed1c2016-02-22 06:42:31 -08001051static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1052 const SkPaint* paint) {
1053 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1054 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001055 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001056 const bool hasImageFilter = paint && paint->getImageFilter();
1057
1058 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1059 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1060 // force to L32
1061 return SkImageInfo::MakeN32(w, h, alphaType);
1062 } else {
1063 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001064 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001065 }
1066}
1067
reed4960eee2015-12-18 07:09:18 -08001068void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1069 const SkRect* bounds = rec.fBounds;
1070 const SkPaint* paint = rec.fPaint;
1071 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1072
reed8c30a812016-04-20 16:36:51 -07001073 SkLazyPaint lazyP;
1074 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1075 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001076 SkMatrix remainder;
1077 SkSize scale;
1078 /*
1079 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1080 * but they do handle scaling. To accommodate this, we do the following:
1081 *
1082 * 1. Stash off the current CTM
1083 * 2. Decompose the CTM into SCALE and REMAINDER
1084 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1085 * contains the REMAINDER
1086 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1087 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1088 * of the original imagefilter, and draw that (via drawSprite)
1089 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1090 *
1091 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1092 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1093 */
reed96a04f32016-04-25 09:25:15 -07001094 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001095 stashedMatrix.decomposeScale(&scale, &remainder))
1096 {
1097 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1098 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1099 SkPaint* p = lazyP.set(*paint);
1100 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1101 SkFilterQuality::kLow_SkFilterQuality,
1102 sk_ref_sp(imageFilter)));
1103 imageFilter = p->getImageFilter();
1104 paint = p;
1105 }
reed8c30a812016-04-20 16:36:51 -07001106
junov@chromium.orga907ac32012-02-24 21:54:07 +00001107 // do this before we create the layer. We don't call the public save() since
1108 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001109 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001110
junov@chromium.orga907ac32012-02-24 21:54:07 +00001111 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001112 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001113 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001114 }
1115
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001116 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1117 // the clipRectBounds() call above?
1118 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001119 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001120 }
1121
reed4960eee2015-12-18 07:09:18 -08001122 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001123 SkPixelGeometry geo = fProps.pixelGeometry();
1124 if (paint) {
reed76033be2015-03-14 10:54:31 -07001125 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001126 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001127 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001128 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001129 }
1130 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001131
robertphillips5139e502016-07-19 05:10:40 -07001132 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001133 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001134 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001135 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001136 }
reedb2db8982014-11-13 12:41:02 -08001137
robertphillips5139e502016-07-19 05:10:40 -07001138 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001139 paint);
1140
Hal Canary704cd322016-11-07 14:13:52 -05001141 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001142 {
reed70ee31b2015-12-10 13:44:45 -08001143 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001144 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001145 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001146 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001147 preserveLCDText,
1148 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001149 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1150 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001151 return;
reed61f501f2015-04-29 08:34:00 -07001152 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001153 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001154 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001155
Mike Reedb43a3e02017-02-11 10:18:58 -05001156 // only have a "next" if this new layer doesn't affect the clip (rare)
1157 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158 fMCRec->fLayer = layer;
1159 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001160
Mike Reedc61abee2017-02-28 17:45:27 -05001161 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001162 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001163 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001164 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001165
Mike Reedc42a1cd2017-02-14 14:25:14 -05001166 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1167
1168 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1169 if (layer->fNext) {
1170 // need to punch a hole in the previous device, so we don't draw there, given that
1171 // the new top-layer will allow drawing to happen "below" it.
1172 SkRegion hole(ir);
1173 do {
1174 layer = layer->fNext;
1175 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1176 } while (layer->fNext);
1177 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001178}
1179
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001180int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001181 if (0xFF == alpha) {
1182 return this->saveLayer(bounds, nullptr);
1183 } else {
1184 SkPaint tmpPaint;
1185 tmpPaint.setAlpha(alpha);
1186 return this->saveLayer(bounds, &tmpPaint);
1187 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001188}
1189
reed@android.com8a1c16f2008-12-17 15:59:43 +00001190void SkCanvas::internalRestore() {
1191 SkASSERT(fMCStack.count() != 0);
1192
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001193 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194 DeviceCM* layer = fMCRec->fLayer; // may be null
1195 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001196 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001197
1198 // now do the normal restore()
1199 fMCRec->~MCRec(); // balanced in save()
1200 fMCStack.pop_back();
1201 fMCRec = (MCRec*)fMCStack.back();
1202
Mike Reedc42a1cd2017-02-14 14:25:14 -05001203 if (fMCRec) {
1204 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1205 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001206
reed@android.com8a1c16f2008-12-17 15:59:43 +00001207 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1208 since if we're being recorded, we don't want to record this (the
1209 recorder will have already recorded the restore).
1210 */
bsalomon49f085d2014-09-05 13:34:00 -07001211 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001212 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001213 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001214 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001215 layer->fPaint.get(),
1216 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001217 // restore what we smashed in internalSaveLayer
1218 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001219 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001220 delete layer;
reedb679ca82015-04-07 04:40:48 -07001221 } else {
1222 // we're at the root
reeda499f902015-05-01 09:34:31 -07001223 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001224 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001225 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001227 }
msarettfbfa2582016-08-12 08:29:08 -07001228
1229 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001230 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001231 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1232 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001233}
1234
reede8f30622016-03-23 18:59:25 -07001235sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001236 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001237 props = &fProps;
1238 }
1239 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001240}
1241
reede8f30622016-03-23 18:59:25 -07001242sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001243 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001244 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001245}
1246
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001247SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001248 return this->onImageInfo();
1249}
1250
1251SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001252 SkBaseDevice* dev = this->getDevice();
1253 if (dev) {
1254 return dev->imageInfo();
1255 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001256 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001257 }
1258}
1259
brianosman898235c2016-04-06 07:38:23 -07001260bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001261 return this->onGetProps(props);
1262}
1263
1264bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001265 SkBaseDevice* dev = this->getDevice();
1266 if (dev) {
1267 if (props) {
1268 *props = fProps;
1269 }
1270 return true;
1271 } else {
1272 return false;
1273 }
1274}
1275
reed6ceeebd2016-03-09 14:26:26 -08001276bool SkCanvas::peekPixels(SkPixmap* pmap) {
1277 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001278}
1279
reed884e97c2015-05-26 11:31:54 -07001280bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001281 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001282 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001283}
1284
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001285void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001286 SkPixmap pmap;
1287 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001288 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001289 }
1290 if (info) {
1291 *info = pmap.info();
1292 }
1293 if (rowBytes) {
1294 *rowBytes = pmap.rowBytes();
1295 }
1296 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001297 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001298 }
reed884e97c2015-05-26 11:31:54 -07001299 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001300}
1301
reed884e97c2015-05-26 11:31:54 -07001302bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001303 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001304 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001305}
1306
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308
Florin Malita53f77bd2017-04-28 13:48:37 -04001309void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1310 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001312 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313 paint = &tmp;
1314 }
reed@google.com4b226022011-01-11 18:32:13 +00001315
reed@google.com8926b162012-03-23 15:36:36 +00001316 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001317
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001319 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001320 paint = &looper.paint();
1321 SkImageFilter* filter = paint->getImageFilter();
1322 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001323 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001324 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1325 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001326 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1327 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001328 }
reed@google.com76dd2772012-01-05 21:15:07 +00001329 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001330 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001331 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 }
reeda2217ef2016-07-20 06:04:34 -07001333
reed@google.com4e2b3d32011-04-07 14:18:59 +00001334 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335}
1336
reed32704672015-12-16 08:27:10 -08001337/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001338
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001339void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001340 if (dx || dy) {
1341 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001342 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001343
reedfe69b502016-09-12 06:31:48 -07001344 // Translate shouldn't affect the is-scale-translateness of the matrix.
1345 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001346
Mike Reedc42a1cd2017-02-14 14:25:14 -05001347 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001348
reedfe69b502016-09-12 06:31:48 -07001349 this->didTranslate(dx,dy);
1350 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001351}
1352
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001353void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001354 SkMatrix m;
1355 m.setScale(sx, sy);
1356 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001357}
1358
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001359void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001360 SkMatrix m;
1361 m.setRotate(degrees);
1362 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001363}
1364
bungeman7438bfc2016-07-12 15:01:19 -07001365void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1366 SkMatrix m;
1367 m.setRotate(degrees, px, py);
1368 this->concat(m);
1369}
1370
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001371void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001372 SkMatrix m;
1373 m.setSkew(sx, sy);
1374 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001375}
1376
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001377void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001378 if (matrix.isIdentity()) {
1379 return;
1380 }
1381
reed2ff1fce2014-12-11 07:07:37 -08001382 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001383 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001384 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001385
Mike Reed7627fa52017-02-08 10:07:53 -05001386 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001387
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001388 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001389}
1390
reed8c30a812016-04-20 16:36:51 -07001391void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001392 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001393 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001394
Mike Reedc42a1cd2017-02-14 14:25:14 -05001395 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001396}
1397
1398void SkCanvas::setMatrix(const SkMatrix& matrix) {
1399 this->checkForDeferredSave();
1400 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001401 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402}
1403
reed@android.com8a1c16f2008-12-17 15:59:43 +00001404void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001405 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001406}
1407
vjiaoblack95302da2016-07-21 10:25:54 -07001408#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001409void SkCanvas::translateZ(SkScalar z) {
1410 this->checkForDeferredSave();
1411 this->fMCRec->fCurDrawDepth += z;
1412 this->didTranslateZ(z);
1413}
1414
1415SkScalar SkCanvas::getZ() const {
1416 return this->fMCRec->fCurDrawDepth;
1417}
1418
vjiaoblack95302da2016-07-21 10:25:54 -07001419void SkCanvas::setLights(sk_sp<SkLights> lights) {
1420 this->fLights = lights;
1421}
1422
1423sk_sp<SkLights> SkCanvas::getLights() const {
1424 return this->fLights;
1425}
1426#endif
1427
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428//////////////////////////////////////////////////////////////////////////////
1429
Mike Reedc1f77742016-12-09 09:00:50 -05001430void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001431 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001432 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1433 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001434}
1435
Mike Reedc1f77742016-12-09 09:00:50 -05001436void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001437 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001438
Mike Reed7627fa52017-02-08 10:07:53 -05001439 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001440
reedc64eff52015-11-21 12:39:45 -08001441 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001442 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1443 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001444 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001445}
1446
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001447void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1448 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001449 if (fClipRestrictionRect.isEmpty()) {
1450 // we notify the device, but we *dont* resolve deferred saves (since we're just
1451 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001452 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001453 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001454 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001455 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001456 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001457 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001458 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1459 }
1460}
1461
Mike Reedc1f77742016-12-09 09:00:50 -05001462void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001463 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001464 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001465 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001466 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1467 } else {
1468 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001469 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001470}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001471
Mike Reedc1f77742016-12-09 09:00:50 -05001472void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001473 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001474
Brian Salomona3b45d42016-10-03 11:36:16 -04001475 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001476
Mike Reed7627fa52017-02-08 10:07:53 -05001477 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001478
Brian Salomona3b45d42016-10-03 11:36:16 -04001479 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1480 isAA);
1481 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001482}
1483
Mike Reedc1f77742016-12-09 09:00:50 -05001484void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001485 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001486 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001487
1488 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1489 SkRect r;
1490 if (path.isRect(&r)) {
1491 this->onClipRect(r, op, edgeStyle);
1492 return;
1493 }
1494 SkRRect rrect;
1495 if (path.isOval(&r)) {
1496 rrect.setOval(r);
1497 this->onClipRRect(rrect, op, edgeStyle);
1498 return;
1499 }
1500 if (path.isRRect(&rrect)) {
1501 this->onClipRRect(rrect, op, edgeStyle);
1502 return;
1503 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001504 }
robertphillips39f05382015-11-24 09:30:12 -08001505
1506 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001507}
1508
Mike Reedc1f77742016-12-09 09:00:50 -05001509void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001510 AutoValidateClip avc(this);
1511
Brian Salomona3b45d42016-10-03 11:36:16 -04001512 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001513
Mike Reed7627fa52017-02-08 10:07:53 -05001514 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001515
Brian Salomona3b45d42016-10-03 11:36:16 -04001516 const SkPath* rasterClipPath = &path;
1517 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001518 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1519 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001520 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001521}
1522
Mike Reedc1f77742016-12-09 09:00:50 -05001523void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001524 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001525 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001526}
1527
Mike Reedc1f77742016-12-09 09:00:50 -05001528void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001529 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001530
reed@google.com5c3d1472011-02-22 19:12:23 +00001531 AutoValidateClip avc(this);
1532
reed73603f32016-09-20 08:42:38 -07001533 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001534 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001535}
1536
reed@google.com819c9212011-02-23 18:56:55 +00001537#ifdef SK_DEBUG
1538void SkCanvas::validateClip() const {
1539 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001540 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001541 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001542 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001543 return;
1544 }
reed@google.com819c9212011-02-23 18:56:55 +00001545}
1546#endif
1547
Mike Reeda1361362017-03-07 09:37:29 -05001548bool SkCanvas::androidFramework_isClipAA() const {
1549 bool containsAA = false;
1550
1551 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1552
1553 return containsAA;
1554}
1555
1556class RgnAccumulator {
1557 SkRegion* fRgn;
1558public:
1559 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1560 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1561 SkIPoint origin = device->getOrigin();
1562 if (origin.x() | origin.y()) {
1563 rgn->translate(origin.x(), origin.y());
1564 }
1565 fRgn->op(*rgn, SkRegion::kUnion_Op);
1566 }
1567};
1568
1569void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1570 RgnAccumulator accum(rgn);
1571 SkRegion tmp;
1572
1573 rgn->setEmpty();
1574 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001575}
1576
reed@google.com5c3d1472011-02-22 19:12:23 +00001577///////////////////////////////////////////////////////////////////////////////
1578
reed@google.com754de5f2014-02-24 19:38:20 +00001579bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001580 return fMCRec->fRasterClip.isEmpty();
1581
1582 // TODO: should we only use the conservative answer in a recording canvas?
1583#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001584 SkBaseDevice* dev = this->getTopDevice();
1585 // if no device we return true
1586 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001587#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001588}
1589
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001590bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001591 SkBaseDevice* dev = this->getTopDevice();
1592 // if no device we return false
1593 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001594}
1595
msarettfbfa2582016-08-12 08:29:08 -07001596static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1597#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1598 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1599 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1600 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1601 return 0xF != _mm_movemask_ps(mask);
1602#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1603 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1604 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1605 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1606 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1607#else
1608 SkRect devRectAsRect;
1609 SkRect devClipAsRect;
1610 devRect.store(&devRectAsRect.fLeft);
1611 devClip.store(&devClipAsRect.fLeft);
1612 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1613#endif
1614}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001615
msarettfbfa2582016-08-12 08:29:08 -07001616// It's important for this function to not be inlined. Otherwise the compiler will share code
1617// between the fast path and the slow path, resulting in two slow paths.
1618static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1619 const SkMatrix& matrix) {
1620 SkRect deviceRect;
1621 matrix.mapRect(&deviceRect, src);
1622 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1623}
1624
1625bool SkCanvas::quickReject(const SkRect& src) const {
1626#ifdef SK_DEBUG
1627 // Verify that fDeviceClipBounds are set properly.
1628 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001629 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001630 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001631 } else {
msarettfbfa2582016-08-12 08:29:08 -07001632 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001633 }
msarettfbfa2582016-08-12 08:29:08 -07001634
msarett9637ea92016-08-18 14:03:30 -07001635 // Verify that fIsScaleTranslate is set properly.
1636 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001637#endif
1638
msarett9637ea92016-08-18 14:03:30 -07001639 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001640 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1641 }
1642
1643 // We inline the implementation of mapScaleTranslate() for the fast path.
1644 float sx = fMCRec->fMatrix.getScaleX();
1645 float sy = fMCRec->fMatrix.getScaleY();
1646 float tx = fMCRec->fMatrix.getTranslateX();
1647 float ty = fMCRec->fMatrix.getTranslateY();
1648 Sk4f scale(sx, sy, sx, sy);
1649 Sk4f trans(tx, ty, tx, ty);
1650
1651 // Apply matrix.
1652 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1653
1654 // Make sure left < right, top < bottom.
1655 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1656 Sk4f min = Sk4f::Min(ltrb, rblt);
1657 Sk4f max = Sk4f::Max(ltrb, rblt);
1658 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1659 // ARM this sequence generates the fastest (a single instruction).
1660 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1661
1662 // Check if the device rect is NaN or outside the clip.
1663 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664}
1665
reed@google.com3b3e8952012-08-16 20:53:31 +00001666bool SkCanvas::quickReject(const SkPath& path) const {
1667 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668}
1669
Mike Reed42e8c532017-01-23 14:09:13 -05001670SkRect SkCanvas::onGetLocalClipBounds() const {
1671 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001672 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001673 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001674 }
1675
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001676 SkMatrix inverse;
1677 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001678 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001679 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001680 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681
Mike Reed42e8c532017-01-23 14:09:13 -05001682 SkRect bounds;
1683 SkRect r;
1684 // adjust it outwards in case we are antialiasing
1685 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001686
Mike Reed42e8c532017-01-23 14:09:13 -05001687 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1688 ibounds.fRight + inset, ibounds.fBottom + inset);
1689 inverse.mapRect(&bounds, r);
1690 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001691}
1692
Mike Reed42e8c532017-01-23 14:09:13 -05001693SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001694 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001695}
1696
reed@android.com8a1c16f2008-12-17 15:59:43 +00001697const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001698 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001699}
1700
Brian Osman11052242016-10-27 14:47:55 -04001701GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001702 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001703 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001704}
1705
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001706GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001707 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001708 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001709}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001710
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001711void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1712 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001713 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001714 if (outer.isEmpty()) {
1715 return;
1716 }
1717 if (inner.isEmpty()) {
1718 this->drawRRect(outer, paint);
1719 return;
1720 }
1721
1722 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001723 // be able to return ...
1724 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001725 //
1726 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001727 if (!outer.getBounds().contains(inner.getBounds())) {
1728 return;
1729 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001730
1731 this->onDrawDRRect(outer, inner, paint);
1732}
1733
reed41af9662015-01-05 07:49:08 -08001734// These need to stop being virtual -- clients need to override the onDraw... versions
1735
1736void SkCanvas::drawPaint(const SkPaint& paint) {
1737 this->onDrawPaint(paint);
1738}
1739
1740void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1741 this->onDrawRect(r, paint);
1742}
1743
msarettdca352e2016-08-26 06:37:45 -07001744void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1745 if (region.isEmpty()) {
1746 return;
1747 }
1748
1749 if (region.isRect()) {
1750 return this->drawIRect(region.getBounds(), paint);
1751 }
1752
1753 this->onDrawRegion(region, paint);
1754}
1755
reed41af9662015-01-05 07:49:08 -08001756void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1757 this->onDrawOval(r, paint);
1758}
1759
1760void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1761 this->onDrawRRect(rrect, paint);
1762}
1763
1764void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1765 this->onDrawPoints(mode, count, pts, paint);
1766}
1767
Mike Reede88a1cb2017-03-17 09:50:46 -04001768void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1769 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001770 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001771 this->onDrawVerticesObject(vertices.get(), mode, paint);
1772}
1773
1774void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1775 RETURN_ON_NULL(vertices);
1776 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001777}
1778
1779void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1780 this->onDrawPath(path, paint);
1781}
1782
reeda85d4d02015-05-06 12:56:48 -07001783void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001784 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001785 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001786}
1787
reede47829b2015-08-06 10:02:53 -07001788void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1789 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001790 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001791 if (dst.isEmpty() || src.isEmpty()) {
1792 return;
1793 }
1794 this->onDrawImageRect(image, &src, dst, paint, constraint);
1795}
reed41af9662015-01-05 07:49:08 -08001796
reed84984ef2015-07-17 07:09:43 -07001797void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1798 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001799 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001800 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001801}
1802
reede47829b2015-08-06 10:02:53 -07001803void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1804 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001805 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001806 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1807 constraint);
1808}
reede47829b2015-08-06 10:02:53 -07001809
reed4c21dc52015-06-25 12:32:03 -07001810void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1811 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001812 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001813 if (dst.isEmpty()) {
1814 return;
1815 }
msarett552bca92016-08-03 06:53:26 -07001816 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1817 this->onDrawImageNine(image, center, dst, paint);
1818 } else {
reede47829b2015-08-06 10:02:53 -07001819 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001820 }
reed4c21dc52015-06-25 12:32:03 -07001821}
1822
msarett16882062016-08-16 09:31:08 -07001823void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1824 const SkPaint* paint) {
1825 RETURN_ON_NULL(image);
1826 if (dst.isEmpty()) {
1827 return;
1828 }
msarett71df2d72016-09-30 12:41:42 -07001829
1830 SkIRect bounds;
1831 Lattice latticePlusBounds = lattice;
1832 if (!latticePlusBounds.fBounds) {
1833 bounds = SkIRect::MakeWH(image->width(), image->height());
1834 latticePlusBounds.fBounds = &bounds;
1835 }
1836
1837 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1838 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001839 } else {
1840 this->drawImageRect(image, dst, paint);
1841 }
1842}
1843
reed41af9662015-01-05 07:49:08 -08001844void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001845 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001846 return;
1847 }
reed41af9662015-01-05 07:49:08 -08001848 this->onDrawBitmap(bitmap, dx, dy, paint);
1849}
1850
reede47829b2015-08-06 10:02:53 -07001851void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001852 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001853 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001854 return;
1855 }
reede47829b2015-08-06 10:02:53 -07001856 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001857}
1858
reed84984ef2015-07-17 07:09:43 -07001859void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1860 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001861 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001862}
1863
reede47829b2015-08-06 10:02:53 -07001864void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1865 SrcRectConstraint constraint) {
1866 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1867 constraint);
1868}
reede47829b2015-08-06 10:02:53 -07001869
reed41af9662015-01-05 07:49:08 -08001870void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1871 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001872 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001873 return;
1874 }
msarett552bca92016-08-03 06:53:26 -07001875 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1876 this->onDrawBitmapNine(bitmap, center, dst, paint);
1877 } else {
reeda5517e22015-07-14 10:54:12 -07001878 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001879 }
reed41af9662015-01-05 07:49:08 -08001880}
1881
msarettc573a402016-08-02 08:05:56 -07001882void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1883 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001884 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001885 return;
1886 }
msarett71df2d72016-09-30 12:41:42 -07001887
1888 SkIRect bounds;
1889 Lattice latticePlusBounds = lattice;
1890 if (!latticePlusBounds.fBounds) {
1891 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1892 latticePlusBounds.fBounds = &bounds;
1893 }
1894
1895 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1896 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001897 } else {
msarett16882062016-08-16 09:31:08 -07001898 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001899 }
msarettc573a402016-08-02 08:05:56 -07001900}
1901
reed71c3c762015-06-24 10:29:17 -07001902void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001903 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001904 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001905 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001906 if (count <= 0) {
1907 return;
1908 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001909 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001910 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001911 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001912}
1913
reedf70b5312016-03-04 16:36:20 -08001914void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1915 if (key) {
1916 this->onDrawAnnotation(rect, key, value);
1917 }
1918}
1919
reede47829b2015-08-06 10:02:53 -07001920void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1921 const SkPaint* paint, SrcRectConstraint constraint) {
1922 if (src) {
1923 this->drawImageRect(image, *src, dst, paint, constraint);
1924 } else {
1925 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1926 dst, paint, constraint);
1927 }
1928}
1929void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1930 const SkPaint* paint, SrcRectConstraint constraint) {
1931 if (src) {
1932 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1933 } else {
1934 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1935 dst, paint, constraint);
1936 }
1937}
1938
reed@android.com8a1c16f2008-12-17 15:59:43 +00001939//////////////////////////////////////////////////////////////////////////////
1940// These are the virtual drawing methods
1941//////////////////////////////////////////////////////////////////////////////
1942
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001943void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001944 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001945 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1946 }
1947}
1948
reed41af9662015-01-05 07:49:08 -08001949void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001950 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001951 this->internalDrawPaint(paint);
1952}
1953
1954void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001955 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001956
1957 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001958 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001959 }
1960
reed@google.com4e2b3d32011-04-07 14:18:59 +00001961 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001962}
1963
reed41af9662015-01-05 07:49:08 -08001964void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1965 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001966 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001967 if ((long)count <= 0) {
1968 return;
1969 }
1970
Mike Reed822128b2017-02-28 16:41:03 -05001971 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001972 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001973 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001974 // special-case 2 points (common for drawing a single line)
1975 if (2 == count) {
1976 r.set(pts[0], pts[1]);
1977 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001978 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001979 }
Mike Reed822128b2017-02-28 16:41:03 -05001980 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001981 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1982 return;
1983 }
1984 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001985 }
reed@google.coma584aed2012-05-16 14:06:02 +00001986
halcanary96fcdcc2015-08-27 07:41:13 -07001987 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001988
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001989 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001990
reed@android.com8a1c16f2008-12-17 15:59:43 +00001991 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001992 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001993 }
reed@google.com4b226022011-01-11 18:32:13 +00001994
reed@google.com4e2b3d32011-04-07 14:18:59 +00001995 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001996}
1997
reed4a167172016-08-18 17:15:25 -07001998static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1999 return ((intptr_t)paint.getImageFilter() |
2000#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2001 (intptr_t)canvas->getDrawFilter() |
2002#endif
2003 (intptr_t)paint.getLooper() ) != 0;
2004}
2005
reed41af9662015-01-05 07:49:08 -08002006void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002007 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002008 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002009 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2010 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2011 SkRect tmp(r);
2012 tmp.sort();
2013
Mike Reed822128b2017-02-28 16:41:03 -05002014 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002015 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2016 return;
2017 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018 }
reed@google.com4b226022011-01-11 18:32:13 +00002019
reed4a167172016-08-18 17:15:25 -07002020 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002021 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002022
reed4a167172016-08-18 17:15:25 -07002023 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002024 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002025 }
2026
2027 LOOPER_END
2028 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002029 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002030 SkDrawIter iter(this);
2031 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002032 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002033 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002034 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002035}
2036
msarett44df6512016-08-25 13:54:30 -07002037void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002038 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002039 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002040 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002041 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2042 return;
2043 }
msarett44df6512016-08-25 13:54:30 -07002044 }
2045
Mike Reed822128b2017-02-28 16:41:03 -05002046 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002047
2048 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002049 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002050 }
2051
2052 LOOPER_END
2053}
2054
reed41af9662015-01-05 07:49:08 -08002055void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002056 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002057 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002058 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002059 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2060 return;
2061 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002062 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002063
Mike Reed822128b2017-02-28 16:41:03 -05002064 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002065
2066 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002067 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002068 }
2069
2070 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002071}
2072
bsalomonac3aa242016-08-19 11:25:19 -07002073void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2074 SkScalar sweepAngle, bool useCenter,
2075 const SkPaint& paint) {
2076 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002077 if (paint.canComputeFastBounds()) {
2078 SkRect storage;
2079 // Note we're using the entire oval as the bounds.
2080 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2081 return;
2082 }
bsalomonac3aa242016-08-19 11:25:19 -07002083 }
2084
Mike Reed822128b2017-02-28 16:41:03 -05002085 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002086
2087 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002088 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002089 }
2090
2091 LOOPER_END
2092}
2093
reed41af9662015-01-05 07:49:08 -08002094void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002095 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002096 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002097 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002098 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2099 return;
2100 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002101 }
2102
2103 if (rrect.isRect()) {
2104 // call the non-virtual version
2105 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002106 return;
2107 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002108 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002109 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2110 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002111 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002112
Mike Reed822128b2017-02-28 16:41:03 -05002113 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002114
2115 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002116 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002117 }
2118
2119 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002120}
2121
Mike Reed822128b2017-02-28 16:41:03 -05002122void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002123 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002124 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002125 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2126 return;
2127 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002128 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002129
Mike Reed822128b2017-02-28 16:41:03 -05002130 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002131
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002132 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002133 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002134 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002135
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002136 LOOPER_END
2137}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002138
reed41af9662015-01-05 07:49:08 -08002139void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002140 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002141 if (!path.isFinite()) {
2142 return;
2143 }
2144
Mike Reed822128b2017-02-28 16:41:03 -05002145 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002146 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002147 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002148 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2149 return;
2150 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002152
Mike Reed822128b2017-02-28 16:41:03 -05002153 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002154 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002155 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002156 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002157 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002158 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002159
Mike Reed822128b2017-02-28 16:41:03 -05002160 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002161
2162 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002163 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002164 }
2165
reed@google.com4e2b3d32011-04-07 14:18:59 +00002166 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002167}
2168
reed262a71b2015-12-05 13:07:27 -08002169bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002170 if (!paint.getImageFilter()) {
2171 return false;
2172 }
2173
2174 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002175 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002176 return false;
2177 }
2178
2179 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2180 // Once we can filter and the filter will return a result larger than itself, we should be
2181 // able to remove this constraint.
2182 // skbug.com/4526
2183 //
2184 SkPoint pt;
2185 ctm.mapXY(x, y, &pt);
2186 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2187 return ir.contains(fMCRec->fRasterClip.getBounds());
2188}
2189
reeda85d4d02015-05-06 12:56:48 -07002190void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002191 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002192 SkRect bounds = SkRect::MakeXYWH(x, y,
2193 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002194 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002195 SkRect tmp = bounds;
2196 if (paint) {
2197 paint->computeFastBounds(tmp, &tmp);
2198 }
2199 if (this->quickReject(tmp)) {
2200 return;
2201 }
reeda85d4d02015-05-06 12:56:48 -07002202 }
halcanary9d524f22016-03-29 09:03:52 -07002203
reeda85d4d02015-05-06 12:56:48 -07002204 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002205 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002206 paint = lazy.init();
2207 }
reed262a71b2015-12-05 13:07:27 -08002208
reeda2217ef2016-07-20 06:04:34 -07002209 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002210 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2211 *paint);
2212 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002213 special = this->getDevice()->makeSpecial(image);
2214 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002215 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002216 }
2217 }
2218
reed262a71b2015-12-05 13:07:27 -08002219 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2220
reeda85d4d02015-05-06 12:56:48 -07002221 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002222 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002223 if (special) {
2224 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002225 iter.fDevice->ctm().mapXY(x, y, &pt);
2226 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002227 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002228 SkScalarRoundToInt(pt.fY), pnt,
2229 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002230 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002231 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002232 }
reeda85d4d02015-05-06 12:56:48 -07002233 }
halcanary9d524f22016-03-29 09:03:52 -07002234
reeda85d4d02015-05-06 12:56:48 -07002235 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002236}
2237
reed41af9662015-01-05 07:49:08 -08002238void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002239 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002240 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002241 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002242 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002243 if (paint) {
2244 paint->computeFastBounds(dst, &storage);
2245 }
2246 if (this->quickReject(storage)) {
2247 return;
2248 }
reeda85d4d02015-05-06 12:56:48 -07002249 }
2250 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002251 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002252 paint = lazy.init();
2253 }
halcanary9d524f22016-03-29 09:03:52 -07002254
senorblancoc41e7e12015-12-07 12:51:30 -08002255 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002256 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002257
reeda85d4d02015-05-06 12:56:48 -07002258 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002259 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002260 }
halcanary9d524f22016-03-29 09:03:52 -07002261
reeda85d4d02015-05-06 12:56:48 -07002262 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002263}
2264
reed41af9662015-01-05 07:49:08 -08002265void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002266 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002267 SkDEBUGCODE(bitmap.validate();)
2268
reed33366972015-10-08 09:22:02 -07002269 if (bitmap.drawsNothing()) {
2270 return;
2271 }
2272
2273 SkLazyPaint lazy;
2274 if (nullptr == paint) {
2275 paint = lazy.init();
2276 }
2277
Mike Reed822128b2017-02-28 16:41:03 -05002278 SkRect bounds;
2279 bitmap.getBounds(&bounds);
2280 bounds.offset(x, y);
2281 bool canFastBounds = paint->canComputeFastBounds();
2282 if (canFastBounds) {
2283 SkRect storage;
2284 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002285 return;
2286 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002287 }
reed@google.com4b226022011-01-11 18:32:13 +00002288
reeda2217ef2016-07-20 06:04:34 -07002289 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002290 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2291 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002292 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002293 special = this->getDevice()->makeSpecial(bitmap);
2294 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002295 drawAsSprite = false;
2296 }
2297 }
2298
Mike Reed822128b2017-02-28 16:41:03 -05002299 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2300
2301 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002302
2303 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002304 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002305 if (special) {
reed262a71b2015-12-05 13:07:27 -08002306 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002307 iter.fDevice->ctm().mapXY(x, y, &pt);
2308 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002309 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002310 SkScalarRoundToInt(pt.fY), pnt,
2311 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002312 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002313 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002314 }
reed33366972015-10-08 09:22:02 -07002315 }
msarettfbfa2582016-08-12 08:29:08 -07002316
reed33366972015-10-08 09:22:02 -07002317 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318}
2319
reed@google.com9987ec32011-09-07 11:57:52 +00002320// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002321void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002322 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002323 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002324 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002325 return;
2326 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002327
halcanary96fcdcc2015-08-27 07:41:13 -07002328 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002329 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002330 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2331 return;
2332 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002333 }
reed@google.com3d608122011-11-21 15:16:16 +00002334
reed@google.com33535f32012-09-25 15:37:50 +00002335 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002336 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002337 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002338 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002339
senorblancoc41e7e12015-12-07 12:51:30 -08002340 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002341 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002342
reed@google.com33535f32012-09-25 15:37:50 +00002343 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002344 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002345 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002346
reed@google.com33535f32012-09-25 15:37:50 +00002347 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002348}
2349
reed41af9662015-01-05 07:49:08 -08002350void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002351 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002352 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002353 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002354 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002355}
2356
reed4c21dc52015-06-25 12:32:03 -07002357void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2358 const SkPaint* paint) {
2359 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002360
halcanary96fcdcc2015-08-27 07:41:13 -07002361 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002362 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002363 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2364 return;
2365 }
reed@google.com3d608122011-11-21 15:16:16 +00002366 }
halcanary9d524f22016-03-29 09:03:52 -07002367
reed4c21dc52015-06-25 12:32:03 -07002368 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002369 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002370 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002371 }
halcanary9d524f22016-03-29 09:03:52 -07002372
senorblancoc41e7e12015-12-07 12:51:30 -08002373 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002374
reed4c21dc52015-06-25 12:32:03 -07002375 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002376 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002377 }
halcanary9d524f22016-03-29 09:03:52 -07002378
reed4c21dc52015-06-25 12:32:03 -07002379 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002380}
2381
reed41af9662015-01-05 07:49:08 -08002382void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2383 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002384 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002385 SkDEBUGCODE(bitmap.validate();)
2386
halcanary96fcdcc2015-08-27 07:41:13 -07002387 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002388 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002389 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2390 return;
2391 }
reed4c21dc52015-06-25 12:32:03 -07002392 }
halcanary9d524f22016-03-29 09:03:52 -07002393
reed4c21dc52015-06-25 12:32:03 -07002394 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002395 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002396 paint = lazy.init();
2397 }
halcanary9d524f22016-03-29 09:03:52 -07002398
senorblancoc41e7e12015-12-07 12:51:30 -08002399 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002400
reed4c21dc52015-06-25 12:32:03 -07002401 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002402 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002403 }
halcanary9d524f22016-03-29 09:03:52 -07002404
reed4c21dc52015-06-25 12:32:03 -07002405 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002406}
2407
msarett16882062016-08-16 09:31:08 -07002408void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2409 const SkPaint* paint) {
2410 if (nullptr == paint || paint->canComputeFastBounds()) {
2411 SkRect storage;
2412 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2413 return;
2414 }
2415 }
2416
2417 SkLazyPaint lazy;
2418 if (nullptr == paint) {
2419 paint = lazy.init();
2420 }
2421
2422 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2423
2424 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002425 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002426 }
2427
2428 LOOPER_END
2429}
2430
2431void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2432 const SkRect& dst, const SkPaint* paint) {
2433 if (nullptr == paint || paint->canComputeFastBounds()) {
2434 SkRect storage;
2435 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2436 return;
2437 }
2438 }
2439
2440 SkLazyPaint lazy;
2441 if (nullptr == paint) {
2442 paint = lazy.init();
2443 }
2444
2445 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2446
2447 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002448 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002449 }
2450
2451 LOOPER_END
2452}
2453
reed@google.comf67e4cf2011-03-15 20:56:58 +00002454class SkDeviceFilteredPaint {
2455public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002456 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002457 uint32_t filteredFlags = device->filterTextFlags(paint);
2458 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002459 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002460 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002461 fPaint = newPaint;
2462 } else {
2463 fPaint = &paint;
2464 }
2465 }
2466
reed@google.comf67e4cf2011-03-15 20:56:58 +00002467 const SkPaint& paint() const { return *fPaint; }
2468
2469private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002470 const SkPaint* fPaint;
2471 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002472};
2473
reed@google.come0d9ce82014-04-23 04:00:17 +00002474void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2475 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002476 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002477
2478 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002479 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002480 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481 }
2482
reed@google.com4e2b3d32011-04-07 14:18:59 +00002483 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484}
2485
reed@google.come0d9ce82014-04-23 04:00:17 +00002486void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2487 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002488 SkPoint textOffset = SkPoint::Make(0, 0);
2489
halcanary96fcdcc2015-08-27 07:41:13 -07002490 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002491
reed@android.com8a1c16f2008-12-17 15:59:43 +00002492 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002493 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002494 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002495 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002497
reed@google.com4e2b3d32011-04-07 14:18:59 +00002498 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002499}
2500
reed@google.come0d9ce82014-04-23 04:00:17 +00002501void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2502 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002503
2504 SkPoint textOffset = SkPoint::Make(0, constY);
2505
halcanary96fcdcc2015-08-27 07:41:13 -07002506 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002507
reed@android.com8a1c16f2008-12-17 15:59:43 +00002508 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002509 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002510 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002511 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002512 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002513
reed@google.com4e2b3d32011-04-07 14:18:59 +00002514 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002515}
2516
reed@google.come0d9ce82014-04-23 04:00:17 +00002517void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2518 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002519 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002520
reed@android.com8a1c16f2008-12-17 15:59:43 +00002521 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002522 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002523 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002524 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002525
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002526 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002527}
2528
reed45561a02016-07-07 12:47:17 -07002529void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2530 const SkRect* cullRect, const SkPaint& paint) {
2531 if (cullRect && this->quickReject(*cullRect)) {
2532 return;
2533 }
2534
2535 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2536
2537 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002538 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002539 }
2540
2541 LOOPER_END
2542}
2543
fmalita00d5c2c2014-08-21 08:53:26 -07002544void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2545 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002546
fmalita85d5eb92015-03-04 11:20:12 -08002547 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002548 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002549 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002550 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002551 SkRect tmp;
2552 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2553 return;
2554 }
2555 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002556 }
2557
fmalita024f9962015-03-03 19:08:17 -08002558 // We cannot filter in the looper as we normally do, because the paint is
2559 // incomplete at this point (text-related attributes are embedded within blob run paints).
2560 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002561 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002562
fmalita85d5eb92015-03-04 11:20:12 -08002563 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002564
fmalitaaa1b9122014-08-28 14:32:24 -07002565 while (iter.next()) {
2566 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002567 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002568 }
2569
fmalitaaa1b9122014-08-28 14:32:24 -07002570 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002571
2572 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002573}
2574
Cary Clark2a475ea2017-04-28 15:35:12 -04002575void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2576 this->drawText(string.c_str(), string.size(), x, y, paint);
2577}
2578
reed@google.come0d9ce82014-04-23 04:00:17 +00002579// These will become non-virtual, so they always call the (virtual) onDraw... method
2580void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2581 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002582 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002583 if (byteLength) {
2584 this->onDrawText(text, byteLength, x, y, paint);
2585 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002586}
2587void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2588 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002589 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002590 if (byteLength) {
2591 this->onDrawPosText(text, byteLength, pos, paint);
2592 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002593}
2594void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2595 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002596 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002597 if (byteLength) {
2598 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2599 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002600}
2601void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2602 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002603 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002604 if (byteLength) {
2605 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2606 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002607}
reed45561a02016-07-07 12:47:17 -07002608void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2609 const SkRect* cullRect, const SkPaint& paint) {
2610 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2611 if (byteLength) {
2612 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2613 }
2614}
fmalita00d5c2c2014-08-21 08:53:26 -07002615void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2616 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002617 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002618 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002619 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002620}
reed@google.come0d9ce82014-04-23 04:00:17 +00002621
Mike Reede88a1cb2017-03-17 09:50:46 -04002622void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2623 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002624 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2625 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2626
2627 while (iter.next()) {
2628 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002629 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002630 }
2631
2632 LOOPER_END
2633}
2634
dandovb3c9d1c2014-08-12 08:34:29 -07002635void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002636 const SkPoint texCoords[4], SkBlendMode bmode,
2637 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002638 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002639 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002640 return;
2641 }
mtklein6cfa73a2014-08-13 13:33:49 -07002642
Mike Reedfaba3712016-11-03 14:45:31 -04002643 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002644}
2645
2646void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002647 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002648 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002649 // Since a patch is always within the convex hull of the control points, we discard it when its
2650 // bounding rectangle is completely outside the current clip.
2651 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002652 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002653 if (this->quickReject(bounds)) {
2654 return;
2655 }
mtklein6cfa73a2014-08-13 13:33:49 -07002656
halcanary96fcdcc2015-08-27 07:41:13 -07002657 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002658
dandovecfff212014-08-04 10:02:00 -07002659 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002660 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002661 }
mtklein6cfa73a2014-08-13 13:33:49 -07002662
dandovecfff212014-08-04 10:02:00 -07002663 LOOPER_END
2664}
2665
reeda8db7282015-07-07 10:22:31 -07002666void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002667 RETURN_ON_NULL(dr);
2668 if (x || y) {
2669 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2670 this->onDrawDrawable(dr, &matrix);
2671 } else {
2672 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002673 }
2674}
2675
reeda8db7282015-07-07 10:22:31 -07002676void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002677 RETURN_ON_NULL(dr);
2678 if (matrix && matrix->isIdentity()) {
2679 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002680 }
reede3b38ce2016-01-08 09:18:44 -08002681 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002682}
2683
2684void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002685 // drawable bounds are no longer reliable (e.g. android displaylist)
2686 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002687 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002688}
2689
reed71c3c762015-06-24 10:29:17 -07002690void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002691 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002692 const SkRect* cull, const SkPaint* paint) {
2693 if (cull && this->quickReject(*cull)) {
2694 return;
2695 }
2696
2697 SkPaint pnt;
2698 if (paint) {
2699 pnt = *paint;
2700 }
halcanary9d524f22016-03-29 09:03:52 -07002701
halcanary96fcdcc2015-08-27 07:41:13 -07002702 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002703 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002704 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002705 }
2706 LOOPER_END
2707}
2708
reedf70b5312016-03-04 16:36:20 -08002709void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2710 SkASSERT(key);
2711
2712 SkPaint paint;
2713 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2714 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002715 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002716 }
2717 LOOPER_END
2718}
2719
reed@android.com8a1c16f2008-12-17 15:59:43 +00002720//////////////////////////////////////////////////////////////////////////////
2721// These methods are NOT virtual, and therefore must call back into virtual
2722// methods, rather than actually drawing themselves.
2723//////////////////////////////////////////////////////////////////////////////
2724
reed374772b2016-10-05 17:33:02 -07002725void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002726 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 SkPaint paint;
2728
2729 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002730 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002731 this->drawPaint(paint);
2732}
2733
2734void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002735 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002736 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002737 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2738}
2739
Mike Reed3661bc92017-02-22 13:21:42 -05002740void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002741 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002743
reed@android.com8a1c16f2008-12-17 15:59:43 +00002744 pts[0].set(x0, y0);
2745 pts[1].set(x1, y1);
2746 this->drawPoints(kLines_PointMode, 2, pts, paint);
2747}
2748
Mike Reed3661bc92017-02-22 13:21:42 -05002749void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002750 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 if (radius < 0) {
2752 radius = 0;
2753 }
2754
2755 SkRect r;
2756 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002757 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758}
2759
2760void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2761 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002762 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002763 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002764 SkRRect rrect;
2765 rrect.setRectXY(r, rx, ry);
2766 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767 } else {
2768 this->drawRect(r, paint);
2769 }
2770}
2771
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2773 SkScalar sweepAngle, bool useCenter,
2774 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002775 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002776 if (oval.isEmpty() || !sweepAngle) {
2777 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778 }
bsalomon21af9ca2016-08-25 12:29:23 -07002779 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780}
2781
2782void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2783 const SkPath& path, SkScalar hOffset,
2784 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002785 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002787
reed@android.com8a1c16f2008-12-17 15:59:43 +00002788 matrix.setTranslate(hOffset, vOffset);
2789 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2790}
2791
reed@android.comf76bacf2009-05-13 14:00:33 +00002792///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002793
2794/**
2795 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2796 * against the playback cost of recursing into the subpicture to get at its actual ops.
2797 *
2798 * For now we pick a conservatively small value, though measurement (and other heuristics like
2799 * the type of ops contained) may justify changing this value.
2800 */
2801#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002802
reedd5fa1a42014-08-09 11:08:05 -07002803void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002804 RETURN_ON_NULL(picture);
2805
reed1c2c4412015-04-30 13:09:24 -07002806 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002807 if (matrix && matrix->isIdentity()) {
2808 matrix = nullptr;
2809 }
2810 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2811 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2812 picture->playback(this);
2813 } else {
2814 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002815 }
2816}
robertphillips9b14f262014-06-04 05:40:44 -07002817
reedd5fa1a42014-08-09 11:08:05 -07002818void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2819 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002820 if (!paint || paint->canComputeFastBounds()) {
2821 SkRect bounds = picture->cullRect();
2822 if (paint) {
2823 paint->computeFastBounds(bounds, &bounds);
2824 }
2825 if (matrix) {
2826 matrix->mapRect(&bounds);
2827 }
2828 if (this->quickReject(bounds)) {
2829 return;
2830 }
2831 }
2832
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002833 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002834 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002835}
2836
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837///////////////////////////////////////////////////////////////////////////////
2838///////////////////////////////////////////////////////////////////////////////
2839
reed3aafe112016-08-18 12:45:34 -07002840SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002841 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842
2843 SkASSERT(canvas);
2844
reed3aafe112016-08-18 12:45:34 -07002845 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002846 fDone = !fImpl->next();
2847}
2848
2849SkCanvas::LayerIter::~LayerIter() {
2850 fImpl->~SkDrawIter();
2851}
2852
2853void SkCanvas::LayerIter::next() {
2854 fDone = !fImpl->next();
2855}
2856
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002857SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002858 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002859}
2860
2861const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002862 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002863}
2864
2865const SkPaint& SkCanvas::LayerIter::paint() const {
2866 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002867 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002868 paint = &fDefaultPaint;
2869 }
2870 return *paint;
2871}
2872
Mike Reeda1361362017-03-07 09:37:29 -05002873void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2874 return fImpl->fDevice->onAsRgnClip(rgn);
2875}
2876
reed@android.com8a1c16f2008-12-17 15:59:43 +00002877int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2878int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002879
2880///////////////////////////////////////////////////////////////////////////////
2881
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002882static bool supported_for_raster_canvas(const SkImageInfo& info) {
2883 switch (info.alphaType()) {
2884 case kPremul_SkAlphaType:
2885 case kOpaque_SkAlphaType:
2886 break;
2887 default:
2888 return false;
2889 }
2890
2891 switch (info.colorType()) {
2892 case kAlpha_8_SkColorType:
2893 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002894 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002895 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002896 break;
2897 default:
2898 return false;
2899 }
2900
2901 return true;
2902}
2903
Mike Reed5df49342016-11-12 08:06:55 -06002904std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
2905 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002906 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002907 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002908 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002909
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002910 SkBitmap bitmap;
2911 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002912 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002913 }
Mike Reed5df49342016-11-12 08:06:55 -06002914 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002915}
reedd5fa1a42014-08-09 11:08:05 -07002916
2917///////////////////////////////////////////////////////////////////////////////
2918
2919SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002920 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002921 : fCanvas(canvas)
2922 , fSaveCount(canvas->getSaveCount())
2923{
bsalomon49f085d2014-09-05 13:34:00 -07002924 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002925 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002926 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002927 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002928 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002929 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002930 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002931 canvas->save();
2932 }
mtklein6cfa73a2014-08-13 13:33:49 -07002933
bsalomon49f085d2014-09-05 13:34:00 -07002934 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002935 canvas->concat(*matrix);
2936 }
2937}
2938
2939SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2940 fCanvas->restoreToCount(fSaveCount);
2941}
reede8f30622016-03-23 18:59:25 -07002942
Florin Malitaee424ac2016-12-01 12:47:59 -05002943///////////////////////////////////////////////////////////////////////////////
2944
2945SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2946 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2947
Florin Malita439ace92016-12-02 12:05:41 -05002948SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2949 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2950
Florin Malitaee424ac2016-12-01 12:47:59 -05002951SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2952 (void)this->INHERITED::getSaveLayerStrategy(rec);
2953 return kNoLayer_SaveLayerStrategy;
2954}
2955
2956///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002957
reed73603f32016-09-20 08:42:38 -07002958static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2959static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2960static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2961static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2962static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2963static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002964
2965///////////////////////////////////////////////////////////////////////////////////////////////////
2966
2967SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2968 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002969 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002970 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2971 SkIPoint origin = dev->getOrigin();
2972 SkMatrix ctm = this->getTotalMatrix();
2973 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2974
2975 SkIRect clip = fMCRec->fRasterClip.getBounds();
2976 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002977 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002978 clip.setEmpty();
2979 }
2980
2981 fAllocator->updateHandle(handle, ctm, clip);
2982 return handle;
2983 }
2984 return nullptr;
2985}
2986
2987static bool install(SkBitmap* bm, const SkImageInfo& info,
2988 const SkRasterHandleAllocator::Rec& rec) {
2989 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
2990 rec.fReleaseProc, rec.fReleaseCtx);
2991}
2992
2993SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2994 SkBitmap* bm) {
2995 SkRasterHandleAllocator::Rec rec;
2996 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2997 return nullptr;
2998 }
2999 return rec.fHandle;
3000}
3001
3002std::unique_ptr<SkCanvas>
3003SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3004 const SkImageInfo& info, const Rec* rec) {
3005 if (!alloc || !supported_for_raster_canvas(info)) {
3006 return nullptr;
3007 }
3008
3009 SkBitmap bm;
3010 Handle hndl;
3011
3012 if (rec) {
3013 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3014 } else {
3015 hndl = alloc->allocBitmap(info, &bm);
3016 }
3017 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3018}