blob: 91a534c3f46cf873bf4d3e65246c40e70f07fcf6 [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"
Florin Malitaab244f02017-05-03 19:16:58 +000023#include "SkLights.h"
Mike Reed5df49342016-11-12 08:06:55 -060024#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080025#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000026#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050027#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070028#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070029#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070030#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000031#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040036#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000037#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070038#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000039#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000040#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080041#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070042#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080045#include "GrContext.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 {}
Hal Canaryb9642382017-06-27 09:58:56 -040092 void drawBitmap(const SkBitmap&, SkScalar x, SkScalar y, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -050093 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
Mike Reeda1361362017-03-07 09:37:29 -0500296 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700297 fFilter = nullptr;
298 fLayer = nullptr;
299 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800300 fMatrix.reset();
301 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700302
reedd9544982014-09-09 18:46:22 -0700303 // don't bother initializing fNext
304 inc_rec();
305 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400306 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700307 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700308 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700309 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800310 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700311
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312 // don't bother initializing fNext
313 inc_rec();
314 }
315 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000316 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700317 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000318 dec_rec();
319 }
mtkleinfeaadee2015-04-08 11:25:48 -0700320
321 void reset(const SkIRect& bounds) {
322 SkASSERT(fLayer);
323 SkASSERT(fDeferredSaveCount == 0);
324
325 fMatrix.reset();
326 fRasterClip.setRect(bounds);
327 fLayer->reset(bounds);
328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329};
330
Mike Reeda1361362017-03-07 09:37:29 -0500331class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332public:
Mike Reeda1361362017-03-07 09:37:29 -0500333 SkDrawIter(SkCanvas* canvas)
334 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
335 {}
reed@google.com4b226022011-01-11 18:32:13 +0000336
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000338 const DeviceCM* rec = fCurrLayer;
339 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400340 fDevice = rec->fDevice.get();
341 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700343 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 return true;
345 }
346 return false;
347 }
reed@google.com4b226022011-01-11 18:32:13 +0000348
reed@google.com6f8f2922011-03-04 22:27:10 +0000349 int getX() const { return fDevice->getOrigin().x(); }
350 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000352
Mike Reed99330ba2017-02-22 11:01:08 -0500353 SkBaseDevice* fDevice;
354
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 const DeviceCM* fCurrLayer;
357 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358};
359
Florin Malita713b8ef2017-04-28 10:57:24 -0400360#define FOR_EACH_TOP_DEVICE( code ) \
361 do { \
362 DeviceCM* layer = fMCRec->fTopLayer; \
363 while (layer) { \
364 SkBaseDevice* device = layer->fDevice.get(); \
365 if (device) { \
366 code; \
367 } \
368 layer = layer->fNext; \
369 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500370 } while (0)
371
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372/////////////////////////////////////////////////////////////////////////////
373
reeddbc3cef2015-04-29 12:18:57 -0700374static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
375 return lazy->isValid() ? lazy->get() : lazy->set(orig);
376}
377
378/**
379 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700380 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700381 */
reedd053ce92016-03-22 10:17:23 -0700382static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700383 SkImageFilter* imgf = paint.getImageFilter();
384 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700385 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700386 }
387
reedd053ce92016-03-22 10:17:23 -0700388 SkColorFilter* imgCFPtr;
389 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700390 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700391 }
reedd053ce92016-03-22 10:17:23 -0700392 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700393
394 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700395 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700396 // there is no existing paint colorfilter, so we can just return the imagefilter's
397 return imgCF;
398 }
399
400 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
401 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700402 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700403}
404
senorblanco87e066e2015-10-28 11:23:36 -0700405/**
406 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
407 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
408 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
409 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
410 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
411 * conservative "effective" bounds based on the settings in the paint... with one exception. This
412 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
413 * deliberately ignored.
414 */
415static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
416 const SkRect& rawBounds,
417 SkRect* storage) {
418 SkPaint tmpUnfiltered(paint);
419 tmpUnfiltered.setImageFilter(nullptr);
420 if (tmpUnfiltered.canComputeFastBounds()) {
421 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
422 } else {
423 return rawBounds;
424 }
425}
426
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427class AutoDrawLooper {
428public:
senorblanco87e066e2015-10-28 11:23:36 -0700429 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
430 // paint. It's used to determine the size of the offscreen layer for filters.
431 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700432 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700433 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000434 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800435#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800437#else
438 fFilter = nullptr;
439#endif
reed4a8126e2014-09-22 07:29:03 -0700440 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000441 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700442 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000443 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444
reedd053ce92016-03-22 10:17:23 -0700445 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700446 if (simplifiedCF) {
447 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700448 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700449 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700450 fPaint = paint;
451 }
452
453 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700454 /**
455 * We implement ImageFilters for a given draw by creating a layer, then applying the
456 * imagefilter to the pixels of that layer (its backing surface/image), and then
457 * we call restore() to xfer that layer to the main canvas.
458 *
459 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
460 * 2. Generate the src pixels:
461 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
462 * return (fPaint). We then draw the primitive (using srcover) into a cleared
463 * buffer/surface.
464 * 3. Restore the layer created in #1
465 * The imagefilter is passed the buffer/surface from the layer (now filled with the
466 * src pixels of the primitive). It returns a new "filtered" buffer, which we
467 * draw onto the previous layer using the xfermode from the original paint.
468 */
reed@google.com8926b162012-03-23 15:36:36 +0000469 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500470 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700471 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700472 SkRect storage;
473 if (rawBounds) {
474 // Make rawBounds include all paint outsets except for those due to image filters.
475 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
476 }
reedbfd5f172016-01-07 11:28:08 -0800477 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700478 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700479 fTempLayerForImageFilter = true;
480 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000481 }
482
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000483 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500484 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000485 fIsSimple = false;
486 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700487 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000488 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700489 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000490 }
491 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000492
reed@android.com8a1c16f2008-12-17 15:59:43 +0000493 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700494 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000495 fCanvas->internalRestore();
496 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000497 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000499
reed@google.com4e2b3d32011-04-07 14:18:59 +0000500 const SkPaint& paint() const {
501 SkASSERT(fPaint);
502 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000504
reed@google.com129ec222012-05-15 13:24:09 +0000505 bool next(SkDrawFilter::Type drawType) {
506 if (fDone) {
507 return false;
508 } else if (fIsSimple) {
509 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000510 return !fPaint->nothingToDraw();
511 } else {
512 return this->doNext(drawType);
513 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500517 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700518 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000519 SkCanvas* fCanvas;
520 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000521 SkDrawFilter* fFilter;
522 const SkPaint* fPaint;
523 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700524 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000525 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000526 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000527 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400528 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000529
530 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000531};
532
reed@google.com129ec222012-05-15 13:24:09 +0000533bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700534 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000535 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700536 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000537
reeddbc3cef2015-04-29 12:18:57 -0700538 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
539 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000540
reed5c476fb2015-04-20 08:04:21 -0700541 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700542 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700543 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000544 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000545
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000546 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000547 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000548 return false;
549 }
550 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000551 if (!fFilter->filter(paint, drawType)) {
552 fDone = true;
553 return false;
554 }
halcanary96fcdcc2015-08-27 07:41:13 -0700555 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000556 // no looper means we only draw once
557 fDone = true;
558 }
559 }
560 fPaint = paint;
561
562 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000563 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000564 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000565 }
566
567 // call this after any possible paint modifiers
568 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700569 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000570 return false;
571 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000572 return true;
573}
574
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575////////// macros to place around the internal draw calls //////////////////
576
reed3aafe112016-08-18 12:45:34 -0700577#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
578 this->predrawNotify(); \
579 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
580 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800581 SkDrawIter iter(this);
582
583
reed@google.com8926b162012-03-23 15:36:36 +0000584#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000585 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700586 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000587 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000588 SkDrawIter iter(this);
589
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000590#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000591 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700592 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000593 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000594 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000595
reedc83a2972015-07-16 07:40:45 -0700596#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
597 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700598 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700599 while (looper.next(type)) { \
600 SkDrawIter iter(this);
601
reed@google.com4e2b3d32011-04-07 14:18:59 +0000602#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603
604////////////////////////////////////////////////////////////////////////////
605
msarettfbfa2582016-08-12 08:29:08 -0700606static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
607 if (bounds.isEmpty()) {
608 return SkRect::MakeEmpty();
609 }
610
611 // Expand bounds out by 1 in case we are anti-aliasing. We store the
612 // bounds as floats to enable a faster quick reject implementation.
613 SkRect dst;
614 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
615 return dst;
616}
617
mtkleinfeaadee2015-04-08 11:25:48 -0700618void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
619 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700620 fMCRec->reset(bounds);
621
622 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500623 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400624 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700625 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700626 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700627}
628
reedd9544982014-09-09 18:46:22 -0700629SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800630 if (device && device->forceConservativeRasterClip()) {
631 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
632 }
reed42b73eb2015-11-20 13:42:42 -0800633
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000634 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800635 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700636 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637
638 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500639 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500640 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700641 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642
reeda499f902015-05-01 09:34:31 -0700643 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
644 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400645 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700646
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648
halcanary96fcdcc2015-08-27 07:41:13 -0700649 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000650
reedf92c8662014-08-18 08:02:43 -0700651 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700652 // The root device and the canvas should always have the same pixel geometry
653 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800654 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700655 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500656
Mike Reedc42a1cd2017-02-14 14:25:14 -0500657 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700658 }
msarettfbfa2582016-08-12 08:29:08 -0700659
reedf92c8662014-08-18 08:02:43 -0700660 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661}
662
reed@google.comcde92112011-07-06 20:00:52 +0000663SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000664 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700665 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000666{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000667 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000668
halcanary96fcdcc2015-08-27 07:41:13 -0700669 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000670}
671
reed96a857e2015-01-25 10:33:58 -0800672SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000673 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800674 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000675{
676 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700677
Mike Reed566e53c2017-03-10 10:49:45 -0500678 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700679 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700680}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000681
reed78e27682014-11-19 08:04:34 -0800682SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700683 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700684 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700685{
686 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700687
Mike Reed566e53c2017-03-10 10:49:45 -0500688 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
689 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700690}
691
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000692SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000693 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700694 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000695{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700697
reedd9544982014-09-09 18:46:22 -0700698 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699}
700
robertphillipsfcf78292015-06-19 11:49:52 -0700701SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
702 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700703 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700704{
705 inc_canvas();
706
707 this->init(device, flags);
708}
709
reed4a8126e2014-09-22 07:29:03 -0700710SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700711 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700712 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700713{
714 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700715
Hal Canary704cd322016-11-07 14:13:52 -0500716 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
717 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700718}
reed29c857d2014-09-21 10:25:07 -0700719
Mike Reed356f7c22017-01-10 11:58:39 -0500720SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
721 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700722 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
723 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500724 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700725{
726 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700727
Mike Reed356f7c22017-01-10 11:58:39 -0500728 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500729 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000730}
731
Mike Reed356f7c22017-01-10 11:58:39 -0500732SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
733
Matt Sarett31f99ce2017-04-11 08:46:01 -0400734#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
735SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
736 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
737 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
738 , fAllocator(nullptr)
739{
740 inc_canvas();
741
742 SkBitmap tmp(bitmap);
743 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
744 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
745 this->init(device.get(), kDefault_InitFlags);
746}
747#endif
748
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749SkCanvas::~SkCanvas() {
750 // free up the contents of our deque
751 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000752
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753 this->internalRestore(); // restore the last, since we're going away
754
halcanary385fe4d2015-08-26 13:07:48 -0700755 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000756
reed@android.com8a1c16f2008-12-17 15:59:43 +0000757 dec_canvas();
758}
759
fmalita53d9f1c2016-01-25 06:23:54 -0800760#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761SkDrawFilter* SkCanvas::getDrawFilter() const {
762 return fMCRec->fFilter;
763}
764
765SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700766 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
768 return filter;
769}
fmalita77650002016-01-21 18:47:11 -0800770#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000772SkMetaData& SkCanvas::getMetaData() {
773 // metadata users are rare, so we lazily allocate it. If that changes we
774 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700775 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000776 fMetaData = new SkMetaData;
777 }
778 return *fMetaData;
779}
780
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781///////////////////////////////////////////////////////////////////////////////
782
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000783void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700784 this->onFlush();
785}
786
787void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000788 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000789 if (device) {
790 device->flush();
791 }
792}
793
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000794SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000795 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000796 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
797}
798
senorblancoafc7cce2016-02-02 18:44:15 -0800799SkIRect SkCanvas::getTopLayerBounds() const {
800 SkBaseDevice* d = this->getTopDevice();
801 if (!d) {
802 return SkIRect::MakeEmpty();
803 }
804 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
805}
806
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000807SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000809 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400811 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812}
813
Florin Malita0ed3b642017-01-13 16:56:38 +0000814SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400815 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000816}
817
Mike Reed353196f2017-07-21 11:01:18 -0400818bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000819 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400820 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000821}
822
Mike Reed353196f2017-07-21 11:01:18 -0400823bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
824 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400825}
826
827bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
828 SkPixmap pm;
829 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
830}
831
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000832bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400833 SkPixmap pm;
834 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700835 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000836 }
837 return false;
838}
839
Matt Sarett03dd6d52017-01-23 12:15:09 -0500840bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000841 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000842 SkBaseDevice* device = this->getDevice();
843 if (!device) {
844 return false;
845 }
846
Matt Sarett03dd6d52017-01-23 12:15:09 -0500847 // This check gives us an early out and prevents generation ID churn on the surface.
848 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
849 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
850 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
851 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000852 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000853
Matt Sarett03dd6d52017-01-23 12:15:09 -0500854 // Tell our owning surface to bump its generation ID.
855 const bool completeOverwrite =
856 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700857 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700858
Matt Sarett03dd6d52017-01-23 12:15:09 -0500859 // This can still fail, most notably in the case of a invalid color type or alpha type
860 // conversion. We could pull those checks into this function and avoid the unnecessary
861 // generation ID bump. But then we would be performing those checks twice, since they
862 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400863 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000864}
reed@google.com51df9e32010-12-23 19:29:18 +0000865
reed@android.com8a1c16f2008-12-17 15:59:43 +0000866//////////////////////////////////////////////////////////////////////////////
867
reed2ff1fce2014-12-11 07:07:37 -0800868void SkCanvas::checkForDeferredSave() {
869 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800870 this->doSave();
871 }
872}
873
reedf0090cb2014-11-26 08:55:51 -0800874int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800875#ifdef SK_DEBUG
876 int count = 0;
877 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
878 for (;;) {
879 const MCRec* rec = (const MCRec*)iter.next();
880 if (!rec) {
881 break;
882 }
883 count += 1 + rec->fDeferredSaveCount;
884 }
885 SkASSERT(count == fSaveCount);
886#endif
887 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800888}
889
890int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800891 fSaveCount += 1;
892 fMCRec->fDeferredSaveCount += 1;
893 return this->getSaveCount() - 1; // return our prev value
894}
895
896void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800897 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700898
899 SkASSERT(fMCRec->fDeferredSaveCount > 0);
900 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800901 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800902}
903
904void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800905 if (fMCRec->fDeferredSaveCount > 0) {
906 SkASSERT(fSaveCount > 1);
907 fSaveCount -= 1;
908 fMCRec->fDeferredSaveCount -= 1;
909 } else {
910 // check for underflow
911 if (fMCStack.count() > 1) {
912 this->willRestore();
913 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700914 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800915 this->internalRestore();
916 this->didRestore();
917 }
reedf0090cb2014-11-26 08:55:51 -0800918 }
919}
920
921void SkCanvas::restoreToCount(int count) {
922 // sanity check
923 if (count < 1) {
924 count = 1;
925 }
mtkleinf0f14112014-12-12 08:46:25 -0800926
reedf0090cb2014-11-26 08:55:51 -0800927 int n = this->getSaveCount() - count;
928 for (int i = 0; i < n; ++i) {
929 this->restore();
930 }
931}
932
reed2ff1fce2014-12-11 07:07:37 -0800933void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000934 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700935 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000936 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000937
Mike Reedc42a1cd2017-02-14 14:25:14 -0500938 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939}
940
reed4960eee2015-12-18 07:09:18 -0800941bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800942 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000943}
944
reed4960eee2015-12-18 07:09:18 -0800945bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700946 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500947 SkIRect clipBounds = this->getDeviceClipBounds();
948 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000949 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000950 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000951
reed96e657d2015-03-10 17:30:07 -0700952 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
953
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000954 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700955 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800956 if (bounds && !imageFilter->canComputeFastBounds()) {
957 bounds = nullptr;
958 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000959 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000960 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700961 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000963
reed96e657d2015-03-10 17:30:07 -0700964 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 r.roundOut(&ir);
966 // early exit if the layer's bounds are clipped out
967 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800968 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500969 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700970 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700971 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000972 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000973 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 }
975 } else { // no user bounds, so just use the clip
976 ir = clipBounds;
977 }
reed180aec42015-03-11 10:39:04 -0700978 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979
reed4960eee2015-12-18 07:09:18 -0800980 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700981 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700982 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700983 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000984 }
985
986 if (intersection) {
987 *intersection = ir;
988 }
989 return true;
990}
991
reed4960eee2015-12-18 07:09:18 -0800992
reed4960eee2015-12-18 07:09:18 -0800993int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
994 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000995}
996
reed70ee31b2015-12-10 13:44:45 -0800997int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800998 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
999}
1000
1001int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001002 SkTCopyOnFirstWrite<SaveLayerRec> rec(origRec);
reed4960eee2015-12-18 07:09:18 -08001003 if (gIgnoreSaveLayerBounds) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001004 rec.writable()->fBounds = nullptr;
reed4960eee2015-12-18 07:09:18 -08001005 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001006
1007 SaveLayerStrategy strategy = this->getSaveLayerStrategy(*rec);
reed4960eee2015-12-18 07:09:18 -08001008 fSaveCount += 1;
Florin Malita53f77bd2017-04-28 13:48:37 -04001009 this->internalSaveLayer(*rec, strategy);
reed4960eee2015-12-18 07:09:18 -08001010 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001011}
1012
reeda2217ef2016-07-20 06:04:34 -07001013void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001014 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001015 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001016 SkDraw draw;
1017 SkRasterClip rc;
1018 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1019 if (!dst->accessPixels(&draw.fDst)) {
1020 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001021 }
reeda2217ef2016-07-20 06:04:34 -07001022 draw.fMatrix = &SkMatrix::I();
1023 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001024
1025 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001026 if (filter) {
1027 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1028 }
reeda2217ef2016-07-20 06:04:34 -07001029
Mike Reedc42a1cd2017-02-14 14:25:14 -05001030 int x = src->getOrigin().x() - dstOrigin.x();
1031 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001032 auto special = src->snapSpecial();
1033 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001034 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -07001035 }
robertphillips7354a4b2015-12-16 05:08:27 -08001036}
reed70ee31b2015-12-10 13:44:45 -08001037
reed129ed1c2016-02-22 06:42:31 -08001038static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1039 const SkPaint* paint) {
1040 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1041 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001042 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001043 const bool hasImageFilter = paint && paint->getImageFilter();
1044
1045 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1046 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1047 // force to L32
1048 return SkImageInfo::MakeN32(w, h, alphaType);
1049 } else {
1050 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001051 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001052 }
1053}
1054
reed4960eee2015-12-18 07:09:18 -08001055void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1056 const SkRect* bounds = rec.fBounds;
1057 const SkPaint* paint = rec.fPaint;
1058 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1059
reed8c30a812016-04-20 16:36:51 -07001060 SkLazyPaint lazyP;
1061 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1062 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001063 SkMatrix remainder;
1064 SkSize scale;
1065 /*
1066 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1067 * but they do handle scaling. To accommodate this, we do the following:
1068 *
1069 * 1. Stash off the current CTM
1070 * 2. Decompose the CTM into SCALE and REMAINDER
1071 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1072 * contains the REMAINDER
1073 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1074 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1075 * of the original imagefilter, and draw that (via drawSprite)
1076 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1077 *
1078 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1079 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1080 */
reed96a04f32016-04-25 09:25:15 -07001081 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001082 stashedMatrix.decomposeScale(&scale, &remainder))
1083 {
1084 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1085 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1086 SkPaint* p = lazyP.set(*paint);
1087 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1088 SkFilterQuality::kLow_SkFilterQuality,
1089 sk_ref_sp(imageFilter)));
1090 imageFilter = p->getImageFilter();
1091 paint = p;
1092 }
reed8c30a812016-04-20 16:36:51 -07001093
junov@chromium.orga907ac32012-02-24 21:54:07 +00001094 // do this before we create the layer. We don't call the public save() since
1095 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001096 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001097
junov@chromium.orga907ac32012-02-24 21:54:07 +00001098 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001099 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001100 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101 }
1102
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001103 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1104 // the clipRectBounds() call above?
1105 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001106 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001107 }
1108
reed4960eee2015-12-18 07:09:18 -08001109 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001110 SkPixelGeometry geo = fProps.pixelGeometry();
1111 if (paint) {
reed76033be2015-03-14 10:54:31 -07001112 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001113 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001114 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001115 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001116 }
1117 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001118
robertphillips5139e502016-07-19 05:10:40 -07001119 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001120 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001121 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001122 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001123 }
reedb2db8982014-11-13 12:41:02 -08001124
robertphillips5139e502016-07-19 05:10:40 -07001125 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001126 paint);
1127
Hal Canary704cd322016-11-07 14:13:52 -05001128 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001129 {
reed70ee31b2015-12-10 13:44:45 -08001130 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001131 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001132 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001133 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001134 preserveLCDText,
1135 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001136 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1137 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001138 return;
reed61f501f2015-04-29 08:34:00 -07001139 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001140 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001141 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142
Mike Reedb43a3e02017-02-11 10:18:58 -05001143 // only have a "next" if this new layer doesn't affect the clip (rare)
1144 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145 fMCRec->fLayer = layer;
1146 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001147
Mike Reedc61abee2017-02-28 17:45:27 -05001148 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001149 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001150 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001151 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001152
Mike Reedc42a1cd2017-02-14 14:25:14 -05001153 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1154
1155 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1156 if (layer->fNext) {
1157 // need to punch a hole in the previous device, so we don't draw there, given that
1158 // the new top-layer will allow drawing to happen "below" it.
1159 SkRegion hole(ir);
1160 do {
1161 layer = layer->fNext;
1162 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1163 } while (layer->fNext);
1164 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001165}
1166
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001167int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001168 if (0xFF == alpha) {
1169 return this->saveLayer(bounds, nullptr);
1170 } else {
1171 SkPaint tmpPaint;
1172 tmpPaint.setAlpha(alpha);
1173 return this->saveLayer(bounds, &tmpPaint);
1174 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001175}
1176
reed@android.com8a1c16f2008-12-17 15:59:43 +00001177void SkCanvas::internalRestore() {
1178 SkASSERT(fMCStack.count() != 0);
1179
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001180 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181 DeviceCM* layer = fMCRec->fLayer; // may be null
1182 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001183 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184
1185 // now do the normal restore()
1186 fMCRec->~MCRec(); // balanced in save()
1187 fMCStack.pop_back();
1188 fMCRec = (MCRec*)fMCStack.back();
1189
Mike Reedc42a1cd2017-02-14 14:25:14 -05001190 if (fMCRec) {
1191 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1192 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001193
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1195 since if we're being recorded, we don't want to record this (the
1196 recorder will have already recorded the restore).
1197 */
bsalomon49f085d2014-09-05 13:34:00 -07001198 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001199 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001200 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001201 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001202 layer->fPaint.get(),
1203 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001204 // restore what we smashed in internalSaveLayer
1205 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001206 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001207 delete layer;
reedb679ca82015-04-07 04:40:48 -07001208 } else {
1209 // we're at the root
reeda499f902015-05-01 09:34:31 -07001210 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001211 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001212 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001213 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001214 }
msarettfbfa2582016-08-12 08:29:08 -07001215
1216 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001217 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001218 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1219 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220}
1221
reede8f30622016-03-23 18:59:25 -07001222sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001223 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001224 props = &fProps;
1225 }
1226 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001227}
1228
reede8f30622016-03-23 18:59:25 -07001229sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001230 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001231 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001232}
1233
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001234SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001235 return this->onImageInfo();
1236}
1237
1238SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001239 SkBaseDevice* dev = this->getDevice();
1240 if (dev) {
1241 return dev->imageInfo();
1242 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001243 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001244 }
1245}
1246
brianosman898235c2016-04-06 07:38:23 -07001247bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001248 return this->onGetProps(props);
1249}
1250
1251bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001252 SkBaseDevice* dev = this->getDevice();
1253 if (dev) {
1254 if (props) {
1255 *props = fProps;
1256 }
1257 return true;
1258 } else {
1259 return false;
1260 }
1261}
1262
reed6ceeebd2016-03-09 14:26:26 -08001263bool SkCanvas::peekPixels(SkPixmap* pmap) {
1264 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001265}
1266
reed884e97c2015-05-26 11:31:54 -07001267bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001268 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001269 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001270}
1271
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001272void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001273 SkPixmap pmap;
1274 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001275 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001276 }
1277 if (info) {
1278 *info = pmap.info();
1279 }
1280 if (rowBytes) {
1281 *rowBytes = pmap.rowBytes();
1282 }
1283 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001284 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001285 }
reed884e97c2015-05-26 11:31:54 -07001286 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001287}
1288
reed884e97c2015-05-26 11:31:54 -07001289bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001290 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001291 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001292}
1293
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295
Florin Malita53f77bd2017-04-28 13:48:37 -04001296void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1297 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001299 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 paint = &tmp;
1301 }
reed@google.com4b226022011-01-11 18:32:13 +00001302
reed@google.com8926b162012-03-23 15:36:36 +00001303 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001304
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001306 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001307 paint = &looper.paint();
1308 SkImageFilter* filter = paint->getImageFilter();
1309 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001310 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001311 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1312 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001313 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1314 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001315 }
reed@google.com76dd2772012-01-05 21:15:07 +00001316 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001317 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001318 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 }
reeda2217ef2016-07-20 06:04:34 -07001320
reed@google.com4e2b3d32011-04-07 14:18:59 +00001321 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322}
1323
reed32704672015-12-16 08:27:10 -08001324/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001325
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001326void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001327 if (dx || dy) {
1328 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001329 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001330
reedfe69b502016-09-12 06:31:48 -07001331 // Translate shouldn't affect the is-scale-translateness of the matrix.
1332 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001333
Mike Reedc42a1cd2017-02-14 14:25:14 -05001334 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001335
reedfe69b502016-09-12 06:31:48 -07001336 this->didTranslate(dx,dy);
1337 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338}
1339
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001340void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001341 SkMatrix m;
1342 m.setScale(sx, sy);
1343 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344}
1345
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001346void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001347 SkMatrix m;
1348 m.setRotate(degrees);
1349 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350}
1351
bungeman7438bfc2016-07-12 15:01:19 -07001352void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1353 SkMatrix m;
1354 m.setRotate(degrees, px, py);
1355 this->concat(m);
1356}
1357
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001358void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001359 SkMatrix m;
1360 m.setSkew(sx, sy);
1361 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001362}
1363
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001364void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001365 if (matrix.isIdentity()) {
1366 return;
1367 }
1368
reed2ff1fce2014-12-11 07:07:37 -08001369 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001370 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001371 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001372
Mike Reed7627fa52017-02-08 10:07:53 -05001373 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001374
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001375 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001376}
1377
reed8c30a812016-04-20 16:36:51 -07001378void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001379 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001380 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001381
Mike Reedc42a1cd2017-02-14 14:25:14 -05001382 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001383}
1384
1385void SkCanvas::setMatrix(const SkMatrix& matrix) {
1386 this->checkForDeferredSave();
1387 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001388 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389}
1390
reed@android.com8a1c16f2008-12-17 15:59:43 +00001391void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001392 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001393}
1394
1395//////////////////////////////////////////////////////////////////////////////
1396
Mike Reedc1f77742016-12-09 09:00:50 -05001397void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001398 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001399 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1400 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001401}
1402
Mike Reedc1f77742016-12-09 09:00:50 -05001403void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001404 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001405
Mike Reed7627fa52017-02-08 10:07:53 -05001406 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001407
reedc64eff52015-11-21 12:39:45 -08001408 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001409 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1410 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001411 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412}
1413
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001414void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1415 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001416 if (fClipRestrictionRect.isEmpty()) {
1417 // we notify the device, but we *dont* resolve deferred saves (since we're just
1418 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001419 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001420 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001421 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001422 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001423 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001424 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001425 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1426 }
1427}
1428
Mike Reedc1f77742016-12-09 09:00:50 -05001429void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001430 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001431 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001432 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001433 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1434 } else {
1435 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001436 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001438
Mike Reedc1f77742016-12-09 09:00:50 -05001439void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001440 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001441
Brian Salomona3b45d42016-10-03 11:36:16 -04001442 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001443
Mike Reed7627fa52017-02-08 10:07:53 -05001444 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001445
Brian Salomona3b45d42016-10-03 11:36:16 -04001446 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1447 isAA);
1448 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001449}
1450
Mike Reedc1f77742016-12-09 09:00:50 -05001451void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001452 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001453 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001454
1455 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1456 SkRect r;
1457 if (path.isRect(&r)) {
1458 this->onClipRect(r, op, edgeStyle);
1459 return;
1460 }
1461 SkRRect rrect;
1462 if (path.isOval(&r)) {
1463 rrect.setOval(r);
1464 this->onClipRRect(rrect, op, edgeStyle);
1465 return;
1466 }
1467 if (path.isRRect(&rrect)) {
1468 this->onClipRRect(rrect, op, edgeStyle);
1469 return;
1470 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001471 }
robertphillips39f05382015-11-24 09:30:12 -08001472
1473 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001474}
1475
Mike Reedc1f77742016-12-09 09:00:50 -05001476void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001477 AutoValidateClip avc(this);
1478
Brian Salomona3b45d42016-10-03 11:36:16 -04001479 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001480
Mike Reed7627fa52017-02-08 10:07:53 -05001481 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482
Brian Salomona3b45d42016-10-03 11:36:16 -04001483 const SkPath* rasterClipPath = &path;
1484 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001485 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1486 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001487 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488}
1489
Mike Reedc1f77742016-12-09 09:00:50 -05001490void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001491 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001492 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001493}
1494
Mike Reedc1f77742016-12-09 09:00:50 -05001495void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001496 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001497
reed@google.com5c3d1472011-02-22 19:12:23 +00001498 AutoValidateClip avc(this);
1499
reed73603f32016-09-20 08:42:38 -07001500 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001501 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001502}
1503
reed@google.com819c9212011-02-23 18:56:55 +00001504#ifdef SK_DEBUG
1505void SkCanvas::validateClip() const {
1506 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001507 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001508 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001509 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001510 return;
1511 }
reed@google.com819c9212011-02-23 18:56:55 +00001512}
1513#endif
1514
Mike Reeda1361362017-03-07 09:37:29 -05001515bool SkCanvas::androidFramework_isClipAA() const {
1516 bool containsAA = false;
1517
1518 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1519
1520 return containsAA;
1521}
1522
1523class RgnAccumulator {
1524 SkRegion* fRgn;
1525public:
1526 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1527 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1528 SkIPoint origin = device->getOrigin();
1529 if (origin.x() | origin.y()) {
1530 rgn->translate(origin.x(), origin.y());
1531 }
1532 fRgn->op(*rgn, SkRegion::kUnion_Op);
1533 }
1534};
1535
1536void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1537 RgnAccumulator accum(rgn);
1538 SkRegion tmp;
1539
1540 rgn->setEmpty();
1541 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001542}
1543
reed@google.com5c3d1472011-02-22 19:12:23 +00001544///////////////////////////////////////////////////////////////////////////////
1545
reed@google.com754de5f2014-02-24 19:38:20 +00001546bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001547 return fMCRec->fRasterClip.isEmpty();
1548
1549 // TODO: should we only use the conservative answer in a recording canvas?
1550#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001551 SkBaseDevice* dev = this->getTopDevice();
1552 // if no device we return true
1553 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001554#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001555}
1556
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001557bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001558 SkBaseDevice* dev = this->getTopDevice();
1559 // if no device we return false
1560 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001561}
1562
msarettfbfa2582016-08-12 08:29:08 -07001563static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1564#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1565 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1566 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1567 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1568 return 0xF != _mm_movemask_ps(mask);
1569#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1570 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1571 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1572 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1573 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1574#else
1575 SkRect devRectAsRect;
1576 SkRect devClipAsRect;
1577 devRect.store(&devRectAsRect.fLeft);
1578 devClip.store(&devClipAsRect.fLeft);
1579 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1580#endif
1581}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001582
msarettfbfa2582016-08-12 08:29:08 -07001583// It's important for this function to not be inlined. Otherwise the compiler will share code
1584// between the fast path and the slow path, resulting in two slow paths.
1585static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1586 const SkMatrix& matrix) {
1587 SkRect deviceRect;
1588 matrix.mapRect(&deviceRect, src);
1589 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1590}
1591
1592bool SkCanvas::quickReject(const SkRect& src) const {
1593#ifdef SK_DEBUG
1594 // Verify that fDeviceClipBounds are set properly.
1595 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001596 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001597 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001598 } else {
msarettfbfa2582016-08-12 08:29:08 -07001599 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001600 }
msarettfbfa2582016-08-12 08:29:08 -07001601
msarett9637ea92016-08-18 14:03:30 -07001602 // Verify that fIsScaleTranslate is set properly.
1603 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001604#endif
1605
msarett9637ea92016-08-18 14:03:30 -07001606 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001607 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1608 }
1609
1610 // We inline the implementation of mapScaleTranslate() for the fast path.
1611 float sx = fMCRec->fMatrix.getScaleX();
1612 float sy = fMCRec->fMatrix.getScaleY();
1613 float tx = fMCRec->fMatrix.getTranslateX();
1614 float ty = fMCRec->fMatrix.getTranslateY();
1615 Sk4f scale(sx, sy, sx, sy);
1616 Sk4f trans(tx, ty, tx, ty);
1617
1618 // Apply matrix.
1619 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1620
1621 // Make sure left < right, top < bottom.
1622 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1623 Sk4f min = Sk4f::Min(ltrb, rblt);
1624 Sk4f max = Sk4f::Max(ltrb, rblt);
1625 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1626 // ARM this sequence generates the fastest (a single instruction).
1627 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1628
1629 // Check if the device rect is NaN or outside the clip.
1630 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001631}
1632
reed@google.com3b3e8952012-08-16 20:53:31 +00001633bool SkCanvas::quickReject(const SkPath& path) const {
1634 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001635}
1636
Mike Reed42e8c532017-01-23 14:09:13 -05001637SkRect SkCanvas::onGetLocalClipBounds() const {
1638 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001639 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001640 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641 }
1642
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001643 SkMatrix inverse;
1644 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001645 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001646 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001647 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648
Mike Reed42e8c532017-01-23 14:09:13 -05001649 SkRect bounds;
1650 SkRect r;
1651 // adjust it outwards in case we are antialiasing
1652 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001653
Mike Reed42e8c532017-01-23 14:09:13 -05001654 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1655 ibounds.fRight + inset, ibounds.fBottom + inset);
1656 inverse.mapRect(&bounds, r);
1657 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658}
1659
Mike Reed42e8c532017-01-23 14:09:13 -05001660SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001661 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001662}
1663
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001665 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001666}
1667
Brian Osman11052242016-10-27 14:47:55 -04001668GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001669 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001670 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001671}
1672
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001673GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001674 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001675 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001676}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001677
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001678void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1679 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001680 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001681 if (outer.isEmpty()) {
1682 return;
1683 }
1684 if (inner.isEmpty()) {
1685 this->drawRRect(outer, paint);
1686 return;
1687 }
1688
1689 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001690 // be able to return ...
1691 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001692 //
1693 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001694 if (!outer.getBounds().contains(inner.getBounds())) {
1695 return;
1696 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001697
1698 this->onDrawDRRect(outer, inner, paint);
1699}
1700
reed41af9662015-01-05 07:49:08 -08001701void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001702 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001703 this->onDrawPaint(paint);
1704}
1705
1706void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001707 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001708 // To avoid redundant logic in our culling code and various backends, we always sort rects
1709 // before passing them along.
1710 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001711}
1712
msarettdca352e2016-08-26 06:37:45 -07001713void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001714 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001715 if (region.isEmpty()) {
1716 return;
1717 }
1718
1719 if (region.isRect()) {
1720 return this->drawIRect(region.getBounds(), paint);
1721 }
1722
1723 this->onDrawRegion(region, paint);
1724}
1725
reed41af9662015-01-05 07:49:08 -08001726void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001727 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001728 // To avoid redundant logic in our culling code and various backends, we always sort rects
1729 // before passing them along.
1730 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001731}
1732
1733void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001734 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001735 this->onDrawRRect(rrect, paint);
1736}
1737
1738void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001739 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001740 this->onDrawPoints(mode, count, pts, paint);
1741}
1742
Mike Reede88a1cb2017-03-17 09:50:46 -04001743void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1744 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001745 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001746 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001747 this->onDrawVerticesObject(vertices.get(), mode, paint);
1748}
1749
1750void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001751 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001752 RETURN_ON_NULL(vertices);
1753 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001754}
1755
1756void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001757 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001758 this->onDrawPath(path, paint);
1759}
1760
reeda85d4d02015-05-06 12:56:48 -07001761void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001762 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001763 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001764 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001765}
1766
reede47829b2015-08-06 10:02:53 -07001767void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1768 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001769 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001770 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001771 if (dst.isEmpty() || src.isEmpty()) {
1772 return;
1773 }
1774 this->onDrawImageRect(image, &src, dst, paint, constraint);
1775}
reed41af9662015-01-05 07:49:08 -08001776
reed84984ef2015-07-17 07:09:43 -07001777void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1778 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001779 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001780 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001781}
1782
reede47829b2015-08-06 10:02:53 -07001783void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1784 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001785 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001786 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1787 constraint);
1788}
reede47829b2015-08-06 10:02:53 -07001789
reed4c21dc52015-06-25 12:32:03 -07001790void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1791 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001792 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001793 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001794 if (dst.isEmpty()) {
1795 return;
1796 }
msarett552bca92016-08-03 06:53:26 -07001797 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1798 this->onDrawImageNine(image, center, dst, paint);
1799 } else {
reede47829b2015-08-06 10:02:53 -07001800 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001801 }
reed4c21dc52015-06-25 12:32:03 -07001802}
1803
msarett16882062016-08-16 09:31:08 -07001804void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1805 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001806 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001807 RETURN_ON_NULL(image);
1808 if (dst.isEmpty()) {
1809 return;
1810 }
msarett71df2d72016-09-30 12:41:42 -07001811
1812 SkIRect bounds;
1813 Lattice latticePlusBounds = lattice;
1814 if (!latticePlusBounds.fBounds) {
1815 bounds = SkIRect::MakeWH(image->width(), image->height());
1816 latticePlusBounds.fBounds = &bounds;
1817 }
1818
1819 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1820 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001821 } else {
1822 this->drawImageRect(image, dst, paint);
1823 }
1824}
1825
reed41af9662015-01-05 07:49:08 -08001826void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001827 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001828 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001829 return;
1830 }
reed41af9662015-01-05 07:49:08 -08001831 this->onDrawBitmap(bitmap, dx, dy, paint);
1832}
1833
reede47829b2015-08-06 10:02:53 -07001834void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001835 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001836 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001837 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001838 return;
1839 }
reede47829b2015-08-06 10:02:53 -07001840 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001841}
1842
reed84984ef2015-07-17 07:09:43 -07001843void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1844 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001845 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001846}
1847
reede47829b2015-08-06 10:02:53 -07001848void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1849 SrcRectConstraint constraint) {
1850 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1851 constraint);
1852}
reede47829b2015-08-06 10:02:53 -07001853
reed41af9662015-01-05 07:49:08 -08001854void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1855 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001856 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001857 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001858 return;
1859 }
msarett552bca92016-08-03 06:53:26 -07001860 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1861 this->onDrawBitmapNine(bitmap, center, dst, paint);
1862 } else {
reeda5517e22015-07-14 10:54:12 -07001863 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001864 }
reed41af9662015-01-05 07:49:08 -08001865}
1866
msarettc573a402016-08-02 08:05:56 -07001867void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1868 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001869 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001870 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001871 return;
1872 }
msarett71df2d72016-09-30 12:41:42 -07001873
1874 SkIRect bounds;
1875 Lattice latticePlusBounds = lattice;
1876 if (!latticePlusBounds.fBounds) {
1877 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1878 latticePlusBounds.fBounds = &bounds;
1879 }
1880
1881 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1882 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001883 } else {
msarett16882062016-08-16 09:31:08 -07001884 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001885 }
msarettc573a402016-08-02 08:05:56 -07001886}
1887
reed71c3c762015-06-24 10:29:17 -07001888void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001889 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001890 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001891 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001892 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001893 if (count <= 0) {
1894 return;
1895 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001896 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001897 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001898 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001899}
1900
reedf70b5312016-03-04 16:36:20 -08001901void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001902 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001903 if (key) {
1904 this->onDrawAnnotation(rect, key, value);
1905 }
1906}
1907
reede47829b2015-08-06 10:02:53 -07001908void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1909 const SkPaint* paint, SrcRectConstraint constraint) {
1910 if (src) {
1911 this->drawImageRect(image, *src, dst, paint, constraint);
1912 } else {
1913 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1914 dst, paint, constraint);
1915 }
1916}
1917void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1918 const SkPaint* paint, SrcRectConstraint constraint) {
1919 if (src) {
1920 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1921 } else {
1922 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1923 dst, paint, constraint);
1924 }
1925}
1926
Mike Reed4204da22017-05-17 08:53:36 -04001927void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001928 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001929 this->onDrawShadowRec(path, rec);
1930}
1931
1932void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1933 SkPaint paint;
1934 const SkRect& pathBounds = path.getBounds();
1935
1936 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1937 while (iter.next()) {
1938 iter.fDevice->drawShadow(path, rec);
1939 }
1940 LOOPER_END
1941}
1942
reed@android.com8a1c16f2008-12-17 15:59:43 +00001943//////////////////////////////////////////////////////////////////////////////
1944// These are the virtual drawing methods
1945//////////////////////////////////////////////////////////////////////////////
1946
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001947void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001948 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001949 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1950 }
1951}
1952
reed41af9662015-01-05 07:49:08 -08001953void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001954 this->internalDrawPaint(paint);
1955}
1956
1957void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001958 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001959
1960 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001961 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001962 }
1963
reed@google.com4e2b3d32011-04-07 14:18:59 +00001964 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001965}
1966
reed41af9662015-01-05 07:49:08 -08001967void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1968 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001969 if ((long)count <= 0) {
1970 return;
1971 }
1972
Mike Reed822128b2017-02-28 16:41:03 -05001973 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001974 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001975 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001976 // special-case 2 points (common for drawing a single line)
1977 if (2 == count) {
1978 r.set(pts[0], pts[1]);
1979 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001980 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001981 }
Mike Reed822128b2017-02-28 16:41:03 -05001982 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001983 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1984 return;
1985 }
1986 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001987 }
reed@google.coma584aed2012-05-16 14:06:02 +00001988
halcanary96fcdcc2015-08-27 07:41:13 -07001989 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001990
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001991 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001992
reed@android.com8a1c16f2008-12-17 15:59:43 +00001993 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001994 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001995 }
reed@google.com4b226022011-01-11 18:32:13 +00001996
reed@google.com4e2b3d32011-04-07 14:18:59 +00001997 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998}
1999
reed4a167172016-08-18 17:15:25 -07002000static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2001 return ((intptr_t)paint.getImageFilter() |
2002#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2003 (intptr_t)canvas->getDrawFilter() |
2004#endif
2005 (intptr_t)paint.getLooper() ) != 0;
2006}
2007
reed41af9662015-01-05 07:49:08 -08002008void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002009 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002010 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002011 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002012 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002013 return;
2014 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002015 }
reed@google.com4b226022011-01-11 18:32:13 +00002016
reed4a167172016-08-18 17:15:25 -07002017 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002018 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002019
reed4a167172016-08-18 17:15:25 -07002020 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002021 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002022 }
2023
2024 LOOPER_END
2025 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002026 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002027 SkDrawIter iter(this);
2028 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002029 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002030 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002031 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002032}
2033
msarett44df6512016-08-25 13:54:30 -07002034void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002035 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002036 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002037 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002038 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2039 return;
2040 }
msarett44df6512016-08-25 13:54:30 -07002041 }
2042
Mike Reed822128b2017-02-28 16:41:03 -05002043 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002044
2045 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002046 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002047 }
2048
2049 LOOPER_END
2050}
2051
reed41af9662015-01-05 07:49:08 -08002052void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002053 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002054 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002055 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002056 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002057 return;
2058 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002059 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002060
Mike Reed822128b2017-02-28 16:41:03 -05002061 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002062
2063 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002064 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002065 }
2066
2067 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002068}
2069
bsalomonac3aa242016-08-19 11:25:19 -07002070void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2071 SkScalar sweepAngle, bool useCenter,
2072 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002073 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002074 if (paint.canComputeFastBounds()) {
2075 SkRect storage;
2076 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002077 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002078 return;
2079 }
bsalomonac3aa242016-08-19 11:25:19 -07002080 }
2081
Mike Reed822128b2017-02-28 16:41:03 -05002082 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002083
2084 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002085 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002086 }
2087
2088 LOOPER_END
2089}
2090
reed41af9662015-01-05 07:49:08 -08002091void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002092 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002093 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002094 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2095 return;
2096 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002097 }
2098
2099 if (rrect.isRect()) {
2100 // call the non-virtual version
2101 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002102 return;
2103 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002104 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002105 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2106 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002107 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002108
Mike Reed822128b2017-02-28 16:41:03 -05002109 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002110
2111 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002112 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002113 }
2114
2115 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002116}
2117
Mike Reed822128b2017-02-28 16:41:03 -05002118void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002119 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002120 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002121 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2122 return;
2123 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002124 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002125
Mike Reed822128b2017-02-28 16:41:03 -05002126 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002127
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002128 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002129 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002130 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002131
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002132 LOOPER_END
2133}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002134
reed41af9662015-01-05 07:49:08 -08002135void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002136 if (!path.isFinite()) {
2137 return;
2138 }
2139
Mike Reed822128b2017-02-28 16:41:03 -05002140 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002141 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002142 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002143 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2144 return;
2145 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002146 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002147
Mike Reed822128b2017-02-28 16:41:03 -05002148 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002149 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002150 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002151 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002152 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002153 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002154
Mike Reed822128b2017-02-28 16:41:03 -05002155 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002156
2157 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002158 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002159 }
2160
reed@google.com4e2b3d32011-04-07 14:18:59 +00002161 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002162}
2163
reed262a71b2015-12-05 13:07:27 -08002164bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002165 if (!paint.getImageFilter()) {
2166 return false;
2167 }
2168
2169 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002170 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002171 return false;
2172 }
2173
2174 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2175 // Once we can filter and the filter will return a result larger than itself, we should be
2176 // able to remove this constraint.
2177 // skbug.com/4526
2178 //
2179 SkPoint pt;
2180 ctm.mapXY(x, y, &pt);
2181 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2182 return ir.contains(fMCRec->fRasterClip.getBounds());
2183}
2184
reeda85d4d02015-05-06 12:56:48 -07002185void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07002186 SkRect bounds = SkRect::MakeXYWH(x, y,
2187 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002188 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002189 SkRect tmp = bounds;
2190 if (paint) {
2191 paint->computeFastBounds(tmp, &tmp);
2192 }
2193 if (this->quickReject(tmp)) {
2194 return;
2195 }
reeda85d4d02015-05-06 12:56:48 -07002196 }
halcanary9d524f22016-03-29 09:03:52 -07002197
reeda85d4d02015-05-06 12:56:48 -07002198 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002199 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002200 paint = lazy.init();
2201 }
reed262a71b2015-12-05 13:07:27 -08002202
reeda2217ef2016-07-20 06:04:34 -07002203 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002204 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2205 *paint);
2206 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002207 special = this->getDevice()->makeSpecial(image);
2208 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002209 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002210 }
2211 }
2212
reed262a71b2015-12-05 13:07:27 -08002213 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2214
reeda85d4d02015-05-06 12:56:48 -07002215 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002216 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002217 if (special) {
2218 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002219 iter.fDevice->ctm().mapXY(x, y, &pt);
2220 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002221 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002222 SkScalarRoundToInt(pt.fY), pnt,
2223 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002224 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002225 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002226 }
reeda85d4d02015-05-06 12:56:48 -07002227 }
halcanary9d524f22016-03-29 09:03:52 -07002228
reeda85d4d02015-05-06 12:56:48 -07002229 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002230}
2231
reed41af9662015-01-05 07:49:08 -08002232void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002233 const SkPaint* paint, SrcRectConstraint constraint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002234 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002235 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002236 if (paint) {
2237 paint->computeFastBounds(dst, &storage);
2238 }
2239 if (this->quickReject(storage)) {
2240 return;
2241 }
reeda85d4d02015-05-06 12:56:48 -07002242 }
2243 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002244 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002245 paint = lazy.init();
2246 }
halcanary9d524f22016-03-29 09:03:52 -07002247
senorblancoc41e7e12015-12-07 12:51:30 -08002248 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002249 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002250
reeda85d4d02015-05-06 12:56:48 -07002251 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002252 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002253 }
halcanary9d524f22016-03-29 09:03:52 -07002254
reeda85d4d02015-05-06 12:56:48 -07002255 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002256}
2257
reed41af9662015-01-05 07:49:08 -08002258void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002259 SkDEBUGCODE(bitmap.validate();)
2260
reed33366972015-10-08 09:22:02 -07002261 if (bitmap.drawsNothing()) {
2262 return;
2263 }
2264
2265 SkLazyPaint lazy;
2266 if (nullptr == paint) {
2267 paint = lazy.init();
2268 }
2269
Mike Reed822128b2017-02-28 16:41:03 -05002270 SkRect bounds;
2271 bitmap.getBounds(&bounds);
2272 bounds.offset(x, y);
2273 bool canFastBounds = paint->canComputeFastBounds();
2274 if (canFastBounds) {
2275 SkRect storage;
2276 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002277 return;
2278 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002279 }
reed@google.com4b226022011-01-11 18:32:13 +00002280
reeda2217ef2016-07-20 06:04:34 -07002281 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002282 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2283 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002284 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002285 special = this->getDevice()->makeSpecial(bitmap);
2286 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002287 drawAsSprite = false;
2288 }
2289 }
2290
Mike Reed822128b2017-02-28 16:41:03 -05002291 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002292
2293 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002294 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002295 if (special) {
reed262a71b2015-12-05 13:07:27 -08002296 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002297 iter.fDevice->ctm().mapXY(x, y, &pt);
2298 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002299 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002300 SkScalarRoundToInt(pt.fY), pnt,
2301 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002302 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002303 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002304 }
reed33366972015-10-08 09:22:02 -07002305 }
msarettfbfa2582016-08-12 08:29:08 -07002306
reed33366972015-10-08 09:22:02 -07002307 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308}
2309
reed@google.com9987ec32011-09-07 11:57:52 +00002310// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002311void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002312 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002313 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002314 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315 return;
2316 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002317
halcanary96fcdcc2015-08-27 07:41:13 -07002318 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002319 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002320 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2321 return;
2322 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002323 }
reed@google.com3d608122011-11-21 15:16:16 +00002324
reed@google.com33535f32012-09-25 15:37:50 +00002325 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002326 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002327 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002329
senorblancoc41e7e12015-12-07 12:51:30 -08002330 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002331 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002332
reed@google.com33535f32012-09-25 15:37:50 +00002333 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002334 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002335 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002336
reed@google.com33535f32012-09-25 15:37:50 +00002337 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002338}
2339
reed41af9662015-01-05 07:49:08 -08002340void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002341 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002342 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002343 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002344}
2345
reed4c21dc52015-06-25 12:32:03 -07002346void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2347 const SkPaint* paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002348 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002349 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002350 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2351 return;
2352 }
reed@google.com3d608122011-11-21 15:16:16 +00002353 }
halcanary9d524f22016-03-29 09:03:52 -07002354
reed4c21dc52015-06-25 12:32:03 -07002355 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002356 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002357 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002358 }
halcanary9d524f22016-03-29 09:03:52 -07002359
senorblancoc41e7e12015-12-07 12:51:30 -08002360 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002361
reed4c21dc52015-06-25 12:32:03 -07002362 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002363 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002364 }
halcanary9d524f22016-03-29 09:03:52 -07002365
reed4c21dc52015-06-25 12:32:03 -07002366 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002367}
2368
reed41af9662015-01-05 07:49:08 -08002369void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2370 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002371 SkDEBUGCODE(bitmap.validate();)
2372
halcanary96fcdcc2015-08-27 07:41:13 -07002373 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002374 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002375 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2376 return;
2377 }
reed4c21dc52015-06-25 12:32:03 -07002378 }
halcanary9d524f22016-03-29 09:03:52 -07002379
reed4c21dc52015-06-25 12:32:03 -07002380 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002381 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002382 paint = lazy.init();
2383 }
halcanary9d524f22016-03-29 09:03:52 -07002384
senorblancoc41e7e12015-12-07 12:51:30 -08002385 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002386
reed4c21dc52015-06-25 12:32:03 -07002387 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002388 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002389 }
halcanary9d524f22016-03-29 09:03:52 -07002390
reed4c21dc52015-06-25 12:32:03 -07002391 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002392}
2393
msarett16882062016-08-16 09:31:08 -07002394void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2395 const SkPaint* paint) {
2396 if (nullptr == paint || paint->canComputeFastBounds()) {
2397 SkRect storage;
2398 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2399 return;
2400 }
2401 }
2402
2403 SkLazyPaint lazy;
2404 if (nullptr == paint) {
2405 paint = lazy.init();
2406 }
2407
2408 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2409
2410 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002411 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002412 }
2413
2414 LOOPER_END
2415}
2416
2417void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2418 const SkRect& dst, const SkPaint* paint) {
2419 if (nullptr == paint || paint->canComputeFastBounds()) {
2420 SkRect storage;
2421 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2422 return;
2423 }
2424 }
2425
2426 SkLazyPaint lazy;
2427 if (nullptr == paint) {
2428 paint = lazy.init();
2429 }
2430
2431 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2432
2433 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002434 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002435 }
2436
2437 LOOPER_END
2438}
2439
reed@google.comf67e4cf2011-03-15 20:56:58 +00002440class SkDeviceFilteredPaint {
2441public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002442 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002443 uint32_t filteredFlags = device->filterTextFlags(paint);
2444 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002445 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002446 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002447 fPaint = newPaint;
2448 } else {
2449 fPaint = &paint;
2450 }
2451 }
2452
reed@google.comf67e4cf2011-03-15 20:56:58 +00002453 const SkPaint& paint() const { return *fPaint; }
2454
2455private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002456 const SkPaint* fPaint;
2457 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002458};
2459
reed@google.come0d9ce82014-04-23 04:00:17 +00002460void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2461 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002462 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002463
2464 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002465 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002466 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002467 }
2468
reed@google.com4e2b3d32011-04-07 14:18:59 +00002469 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002470}
2471
reed@google.come0d9ce82014-04-23 04:00:17 +00002472void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2473 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002474 SkPoint textOffset = SkPoint::Make(0, 0);
2475
halcanary96fcdcc2015-08-27 07:41:13 -07002476 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002477
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478 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->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002481 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002483
reed@google.com4e2b3d32011-04-07 14:18:59 +00002484 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002485}
2486
reed@google.come0d9ce82014-04-23 04:00:17 +00002487void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2488 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002489
2490 SkPoint textOffset = SkPoint::Make(0, constY);
2491
halcanary96fcdcc2015-08-27 07:41:13 -07002492 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002493
reed@android.com8a1c16f2008-12-17 15:59:43 +00002494 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002495 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002496 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002497 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002498 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002499
reed@google.com4e2b3d32011-04-07 14:18:59 +00002500 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002501}
2502
reed@google.come0d9ce82014-04-23 04:00:17 +00002503void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2504 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002505 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002506
reed@android.com8a1c16f2008-12-17 15:59:43 +00002507 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002508 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002509 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002510 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002511
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002512 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002513}
2514
reed45561a02016-07-07 12:47:17 -07002515void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2516 const SkRect* cullRect, const SkPaint& paint) {
2517 if (cullRect && this->quickReject(*cullRect)) {
2518 return;
2519 }
2520
2521 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2522
2523 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002524 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002525 }
2526
2527 LOOPER_END
2528}
2529
fmalita00d5c2c2014-08-21 08:53:26 -07002530void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2531 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002532
fmalita85d5eb92015-03-04 11:20:12 -08002533 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002534 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002535 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002536 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002537 SkRect tmp;
2538 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2539 return;
2540 }
2541 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002542 }
2543
fmalita024f9962015-03-03 19:08:17 -08002544 // We cannot filter in the looper as we normally do, because the paint is
2545 // incomplete at this point (text-related attributes are embedded within blob run paints).
2546 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002547 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002548
fmalita85d5eb92015-03-04 11:20:12 -08002549 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002550
fmalitaaa1b9122014-08-28 14:32:24 -07002551 while (iter.next()) {
2552 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002553 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002554 }
2555
fmalitaaa1b9122014-08-28 14:32:24 -07002556 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002557
2558 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002559}
2560
Cary Clark2a475ea2017-04-28 15:35:12 -04002561void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2562 this->drawText(string.c_str(), string.size(), x, y, paint);
2563}
2564
reed@google.come0d9ce82014-04-23 04:00:17 +00002565// These will become non-virtual, so they always call the (virtual) onDraw... method
2566void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2567 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002568 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002569 if (byteLength) {
2570 this->onDrawText(text, byteLength, x, y, paint);
2571 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002572}
2573void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2574 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002575 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002576 if (byteLength) {
2577 this->onDrawPosText(text, byteLength, pos, paint);
2578 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002579}
2580void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2581 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002582 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002583 if (byteLength) {
2584 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2585 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002586}
2587void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2588 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002589 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002590 if (byteLength) {
2591 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2592 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002593}
reed45561a02016-07-07 12:47:17 -07002594void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2595 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002596 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002597 if (byteLength) {
2598 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2599 }
2600}
fmalita00d5c2c2014-08-21 08:53:26 -07002601void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2602 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002603 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002604 RETURN_ON_NULL(blob);
reede3b38ce2016-01-08 09:18:44 -08002605 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002606}
reed@google.come0d9ce82014-04-23 04:00:17 +00002607
Mike Reede88a1cb2017-03-17 09:50:46 -04002608void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2609 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002610 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2611
2612 while (iter.next()) {
2613 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002614 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002615 }
2616
2617 LOOPER_END
2618}
2619
dandovb3c9d1c2014-08-12 08:34:29 -07002620void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002621 const SkPoint texCoords[4], SkBlendMode bmode,
2622 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002623 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002624 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002625 return;
2626 }
mtklein6cfa73a2014-08-13 13:33:49 -07002627
Mike Reedfaba3712016-11-03 14:45:31 -04002628 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002629}
2630
2631void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002632 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002633 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002634 // Since a patch is always within the convex hull of the control points, we discard it when its
2635 // bounding rectangle is completely outside the current clip.
2636 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002637 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002638 if (this->quickReject(bounds)) {
2639 return;
2640 }
mtklein6cfa73a2014-08-13 13:33:49 -07002641
Mike Reed435071e2017-05-23 11:22:56 -04002642 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2643
halcanary96fcdcc2015-08-27 07:41:13 -07002644 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002645
dandovecfff212014-08-04 10:02:00 -07002646 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002647 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002648 }
mtklein6cfa73a2014-08-13 13:33:49 -07002649
dandovecfff212014-08-04 10:02:00 -07002650 LOOPER_END
2651}
2652
reeda8db7282015-07-07 10:22:31 -07002653void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002654 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002655 RETURN_ON_NULL(dr);
2656 if (x || y) {
2657 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2658 this->onDrawDrawable(dr, &matrix);
2659 } else {
2660 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002661 }
2662}
2663
reeda8db7282015-07-07 10:22:31 -07002664void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002665 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002666 RETURN_ON_NULL(dr);
2667 if (matrix && matrix->isIdentity()) {
2668 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002669 }
reede3b38ce2016-01-08 09:18:44 -08002670 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002671}
2672
2673void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002674 // drawable bounds are no longer reliable (e.g. android displaylist)
2675 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002676 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002677}
2678
reed71c3c762015-06-24 10:29:17 -07002679void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002680 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002681 const SkRect* cull, const SkPaint* paint) {
2682 if (cull && this->quickReject(*cull)) {
2683 return;
2684 }
2685
2686 SkPaint pnt;
2687 if (paint) {
2688 pnt = *paint;
2689 }
halcanary9d524f22016-03-29 09:03:52 -07002690
halcanary96fcdcc2015-08-27 07:41:13 -07002691 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002692 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002693 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002694 }
2695 LOOPER_END
2696}
2697
reedf70b5312016-03-04 16:36:20 -08002698void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2699 SkASSERT(key);
2700
2701 SkPaint paint;
2702 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2703 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002704 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002705 }
2706 LOOPER_END
2707}
2708
reed@android.com8a1c16f2008-12-17 15:59:43 +00002709//////////////////////////////////////////////////////////////////////////////
2710// These methods are NOT virtual, and therefore must call back into virtual
2711// methods, rather than actually drawing themselves.
2712//////////////////////////////////////////////////////////////////////////////
2713
reed374772b2016-10-05 17:33:02 -07002714void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002715 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002717 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002718 this->drawPaint(paint);
2719}
2720
2721void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002722 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2724}
2725
Mike Reed3661bc92017-02-22 13:21:42 -05002726void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728 pts[0].set(x0, y0);
2729 pts[1].set(x1, y1);
2730 this->drawPoints(kLines_PointMode, 2, pts, paint);
2731}
2732
Mike Reed3661bc92017-02-22 13:21:42 -05002733void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002734 if (radius < 0) {
2735 radius = 0;
2736 }
2737
2738 SkRect r;
2739 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002740 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741}
2742
2743void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2744 const SkPaint& paint) {
2745 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002746 SkRRect rrect;
2747 rrect.setRectXY(r, rx, ry);
2748 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002749 } else {
2750 this->drawRect(r, paint);
2751 }
2752}
2753
reed@android.com8a1c16f2008-12-17 15:59:43 +00002754void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2755 SkScalar sweepAngle, bool useCenter,
2756 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002757 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002758 if (oval.isEmpty() || !sweepAngle) {
2759 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002760 }
bsalomon21af9ca2016-08-25 12:29:23 -07002761 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762}
2763
2764void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2765 const SkPath& path, SkScalar hOffset,
2766 SkScalar vOffset, const SkPaint& paint) {
2767 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002768
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769 matrix.setTranslate(hOffset, vOffset);
2770 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2771}
2772
reed@android.comf76bacf2009-05-13 14:00:33 +00002773///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002774
2775/**
2776 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2777 * against the playback cost of recursing into the subpicture to get at its actual ops.
2778 *
2779 * For now we pick a conservatively small value, though measurement (and other heuristics like
2780 * the type of ops contained) may justify changing this value.
2781 */
2782#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002783
reedd5fa1a42014-08-09 11:08:05 -07002784void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002785 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002786 RETURN_ON_NULL(picture);
2787
reede3b38ce2016-01-08 09:18:44 -08002788 if (matrix && matrix->isIdentity()) {
2789 matrix = nullptr;
2790 }
2791 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2792 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2793 picture->playback(this);
2794 } else {
2795 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002796 }
2797}
robertphillips9b14f262014-06-04 05:40:44 -07002798
reedd5fa1a42014-08-09 11:08:05 -07002799void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2800 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002801 if (!paint || paint->canComputeFastBounds()) {
2802 SkRect bounds = picture->cullRect();
2803 if (paint) {
2804 paint->computeFastBounds(bounds, &bounds);
2805 }
2806 if (matrix) {
2807 matrix->mapRect(&bounds);
2808 }
2809 if (this->quickReject(bounds)) {
2810 return;
2811 }
2812 }
2813
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002814 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002815 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816}
2817
reed@android.com8a1c16f2008-12-17 15:59:43 +00002818///////////////////////////////////////////////////////////////////////////////
2819///////////////////////////////////////////////////////////////////////////////
2820
reed3aafe112016-08-18 12:45:34 -07002821SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002822 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823
2824 SkASSERT(canvas);
2825
reed3aafe112016-08-18 12:45:34 -07002826 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002827 fDone = !fImpl->next();
2828}
2829
2830SkCanvas::LayerIter::~LayerIter() {
2831 fImpl->~SkDrawIter();
2832}
2833
2834void SkCanvas::LayerIter::next() {
2835 fDone = !fImpl->next();
2836}
2837
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002838SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002839 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840}
2841
2842const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002843 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002844}
2845
2846const SkPaint& SkCanvas::LayerIter::paint() const {
2847 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002848 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849 paint = &fDefaultPaint;
2850 }
2851 return *paint;
2852}
2853
Mike Reeda1361362017-03-07 09:37:29 -05002854void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2855 return fImpl->fDevice->onAsRgnClip(rgn);
2856}
2857
reed@android.com8a1c16f2008-12-17 15:59:43 +00002858int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2859int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002860
2861///////////////////////////////////////////////////////////////////////////////
2862
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002863static bool supported_for_raster_canvas(const SkImageInfo& info) {
2864 switch (info.alphaType()) {
2865 case kPremul_SkAlphaType:
2866 case kOpaque_SkAlphaType:
2867 break;
2868 default:
2869 return false;
2870 }
2871
2872 switch (info.colorType()) {
2873 case kAlpha_8_SkColorType:
2874 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002875 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002876 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002877 break;
2878 default:
2879 return false;
2880 }
2881
2882 return true;
2883}
2884
Mike Reed5df49342016-11-12 08:06:55 -06002885std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
2886 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002887 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002888 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002889 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002890
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002891 SkBitmap bitmap;
2892 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002893 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002894 }
Mike Reed5df49342016-11-12 08:06:55 -06002895 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002896}
reedd5fa1a42014-08-09 11:08:05 -07002897
2898///////////////////////////////////////////////////////////////////////////////
2899
2900SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002901 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002902 : fCanvas(canvas)
2903 , fSaveCount(canvas->getSaveCount())
2904{
bsalomon49f085d2014-09-05 13:34:00 -07002905 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002906 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002907 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002908 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002909 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002910 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002911 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002912 canvas->save();
2913 }
mtklein6cfa73a2014-08-13 13:33:49 -07002914
bsalomon49f085d2014-09-05 13:34:00 -07002915 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002916 canvas->concat(*matrix);
2917 }
2918}
2919
2920SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2921 fCanvas->restoreToCount(fSaveCount);
2922}
reede8f30622016-03-23 18:59:25 -07002923
Florin Malitaee424ac2016-12-01 12:47:59 -05002924///////////////////////////////////////////////////////////////////////////////
2925
2926SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2927 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2928
Florin Malita439ace92016-12-02 12:05:41 -05002929SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2930 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2931
Florin Malitaee424ac2016-12-01 12:47:59 -05002932SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2933 (void)this->INHERITED::getSaveLayerStrategy(rec);
2934 return kNoLayer_SaveLayerStrategy;
2935}
2936
2937///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002938
reed73603f32016-09-20 08:42:38 -07002939static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2940static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2941static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2942static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2943static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2944static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002945
2946///////////////////////////////////////////////////////////////////////////////////////////////////
2947
2948SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2949 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002950 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002951 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2952 SkIPoint origin = dev->getOrigin();
2953 SkMatrix ctm = this->getTotalMatrix();
2954 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2955
2956 SkIRect clip = fMCRec->fRasterClip.getBounds();
2957 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002958 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002959 clip.setEmpty();
2960 }
2961
2962 fAllocator->updateHandle(handle, ctm, clip);
2963 return handle;
2964 }
2965 return nullptr;
2966}
2967
2968static bool install(SkBitmap* bm, const SkImageInfo& info,
2969 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002970 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002971}
2972
2973SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2974 SkBitmap* bm) {
2975 SkRasterHandleAllocator::Rec rec;
2976 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2977 return nullptr;
2978 }
2979 return rec.fHandle;
2980}
2981
2982std::unique_ptr<SkCanvas>
2983SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2984 const SkImageInfo& info, const Rec* rec) {
2985 if (!alloc || !supported_for_raster_canvas(info)) {
2986 return nullptr;
2987 }
2988
2989 SkBitmap bm;
2990 Handle hndl;
2991
2992 if (rec) {
2993 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2994 } else {
2995 hndl = alloc->allocBitmap(info, &bm);
2996 }
2997 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2998}