blob: 7fbb952d221ce307735199dc7a3d6d6b8c4855f8 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Ben Wagner4bd3b092017-08-01 13:22:23 -040026#include "SkMSAN.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;
reed96e657d2015-03-10 17:30:07 -0700963 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 r.roundOut(&ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 } else { // no user bounds, so just use the clip
966 ir = clipBounds;
967 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800968
969 // early exit if the layer's bounds are clipped out
970 if (!ir.intersect(clipBounds)) {
971 if (BoundsAffectsClip(saveLayerFlags)) {
972 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
973 fMCRec->fRasterClip.setEmpty();
974 fDeviceClipBounds.setEmpty();
975 }
976 return false;
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;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001061 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001062 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) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001398 if (!rect.isFinite()) {
1399 return;
1400 }
reed2ff1fce2014-12-11 07:07:37 -08001401 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001402 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1403 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001404}
1405
Mike Reedc1f77742016-12-09 09:00:50 -05001406void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001407 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001408
Mike Reed7627fa52017-02-08 10:07:53 -05001409 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001410
reedc64eff52015-11-21 12:39:45 -08001411 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001412 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1413 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001414 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415}
1416
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001417void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1418 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001419 if (fClipRestrictionRect.isEmpty()) {
1420 // we notify the device, but we *dont* resolve deferred saves (since we're just
1421 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001422 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001423 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001424 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001425 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001426 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001427 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001428 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1429 }
1430}
1431
Mike Reedc1f77742016-12-09 09:00:50 -05001432void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001433 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001434 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001435 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001436 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1437 } else {
1438 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001439 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001440}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001441
Mike Reedc1f77742016-12-09 09:00:50 -05001442void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001443 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001444
Brian Salomona3b45d42016-10-03 11:36:16 -04001445 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001446
Mike Reed7627fa52017-02-08 10:07:53 -05001447 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001448
Mike Reed20800c82017-11-15 16:09:04 -05001449 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1450 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001451 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001452}
1453
Mike Reedc1f77742016-12-09 09:00:50 -05001454void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001455 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001456 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001457
1458 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1459 SkRect r;
1460 if (path.isRect(&r)) {
1461 this->onClipRect(r, op, edgeStyle);
1462 return;
1463 }
1464 SkRRect rrect;
1465 if (path.isOval(&r)) {
1466 rrect.setOval(r);
1467 this->onClipRRect(rrect, op, edgeStyle);
1468 return;
1469 }
1470 if (path.isRRect(&rrect)) {
1471 this->onClipRRect(rrect, op, edgeStyle);
1472 return;
1473 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001474 }
robertphillips39f05382015-11-24 09:30:12 -08001475
1476 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001477}
1478
Mike Reedc1f77742016-12-09 09:00:50 -05001479void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001480 AutoValidateClip avc(this);
1481
Brian Salomona3b45d42016-10-03 11:36:16 -04001482 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001483
Mike Reed7627fa52017-02-08 10:07:53 -05001484 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485
Brian Salomona3b45d42016-10-03 11:36:16 -04001486 const SkPath* rasterClipPath = &path;
1487 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001488 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1489 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001490 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001491}
1492
Mike Reedc1f77742016-12-09 09:00:50 -05001493void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001494 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001495 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001496}
1497
Mike Reedc1f77742016-12-09 09:00:50 -05001498void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001499 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001500
reed@google.com5c3d1472011-02-22 19:12:23 +00001501 AutoValidateClip avc(this);
1502
Mike Reed20800c82017-11-15 16:09:04 -05001503 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001504 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505}
1506
reed@google.com819c9212011-02-23 18:56:55 +00001507#ifdef SK_DEBUG
1508void SkCanvas::validateClip() const {
1509 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001510 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001511 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001512 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001513 return;
1514 }
reed@google.com819c9212011-02-23 18:56:55 +00001515}
1516#endif
1517
Mike Reeda1361362017-03-07 09:37:29 -05001518bool SkCanvas::androidFramework_isClipAA() const {
1519 bool containsAA = false;
1520
1521 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1522
1523 return containsAA;
1524}
1525
1526class RgnAccumulator {
1527 SkRegion* fRgn;
1528public:
1529 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1530 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1531 SkIPoint origin = device->getOrigin();
1532 if (origin.x() | origin.y()) {
1533 rgn->translate(origin.x(), origin.y());
1534 }
1535 fRgn->op(*rgn, SkRegion::kUnion_Op);
1536 }
1537};
1538
1539void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1540 RgnAccumulator accum(rgn);
1541 SkRegion tmp;
1542
1543 rgn->setEmpty();
1544 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001545}
1546
reed@google.com5c3d1472011-02-22 19:12:23 +00001547///////////////////////////////////////////////////////////////////////////////
1548
reed@google.com754de5f2014-02-24 19:38:20 +00001549bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001550 return fMCRec->fRasterClip.isEmpty();
1551
1552 // TODO: should we only use the conservative answer in a recording canvas?
1553#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001554 SkBaseDevice* dev = this->getTopDevice();
1555 // if no device we return true
1556 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001557#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001558}
1559
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001560bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001561 SkBaseDevice* dev = this->getTopDevice();
1562 // if no device we return false
1563 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001564}
1565
msarettfbfa2582016-08-12 08:29:08 -07001566static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1567#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1568 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1569 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1570 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1571 return 0xF != _mm_movemask_ps(mask);
1572#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1573 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1574 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1575 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1576 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1577#else
1578 SkRect devRectAsRect;
1579 SkRect devClipAsRect;
1580 devRect.store(&devRectAsRect.fLeft);
1581 devClip.store(&devClipAsRect.fLeft);
1582 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1583#endif
1584}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001585
msarettfbfa2582016-08-12 08:29:08 -07001586// It's important for this function to not be inlined. Otherwise the compiler will share code
1587// between the fast path and the slow path, resulting in two slow paths.
1588static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1589 const SkMatrix& matrix) {
1590 SkRect deviceRect;
1591 matrix.mapRect(&deviceRect, src);
1592 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1593}
1594
1595bool SkCanvas::quickReject(const SkRect& src) const {
1596#ifdef SK_DEBUG
1597 // Verify that fDeviceClipBounds are set properly.
1598 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001599 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001600 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001601 } else {
msarettfbfa2582016-08-12 08:29:08 -07001602 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001603 }
msarettfbfa2582016-08-12 08:29:08 -07001604
msarett9637ea92016-08-18 14:03:30 -07001605 // Verify that fIsScaleTranslate is set properly.
1606 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001607#endif
1608
msarett9637ea92016-08-18 14:03:30 -07001609 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001610 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1611 }
1612
1613 // We inline the implementation of mapScaleTranslate() for the fast path.
1614 float sx = fMCRec->fMatrix.getScaleX();
1615 float sy = fMCRec->fMatrix.getScaleY();
1616 float tx = fMCRec->fMatrix.getTranslateX();
1617 float ty = fMCRec->fMatrix.getTranslateY();
1618 Sk4f scale(sx, sy, sx, sy);
1619 Sk4f trans(tx, ty, tx, ty);
1620
1621 // Apply matrix.
1622 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1623
1624 // Make sure left < right, top < bottom.
1625 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1626 Sk4f min = Sk4f::Min(ltrb, rblt);
1627 Sk4f max = Sk4f::Max(ltrb, rblt);
1628 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1629 // ARM this sequence generates the fastest (a single instruction).
1630 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1631
1632 // Check if the device rect is NaN or outside the clip.
1633 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001634}
1635
reed@google.com3b3e8952012-08-16 20:53:31 +00001636bool SkCanvas::quickReject(const SkPath& path) const {
1637 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001638}
1639
Mike Klein83c8dd92017-11-28 17:08:45 -05001640SkRect SkCanvas::getLocalClipBounds() const {
1641 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001642 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001643 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001644 }
1645
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001646 SkMatrix inverse;
1647 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001648 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001649 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001650 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001651
Mike Reed42e8c532017-01-23 14:09:13 -05001652 SkRect bounds;
1653 SkRect r;
1654 // adjust it outwards in case we are antialiasing
1655 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001656
Mike Reed42e8c532017-01-23 14:09:13 -05001657 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1658 ibounds.fRight + inset, ibounds.fBottom + inset);
1659 inverse.mapRect(&bounds, r);
1660 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001661}
1662
Mike Klein83c8dd92017-11-28 17:08:45 -05001663SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001664 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001665}
1666
reed@android.com8a1c16f2008-12-17 15:59:43 +00001667const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001668 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001669}
1670
Brian Osman11052242016-10-27 14:47:55 -04001671GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001672 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001673 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001674}
1675
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001676GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001677 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001678 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001679}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001680
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001681void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1682 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001683 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001684 if (outer.isEmpty()) {
1685 return;
1686 }
1687 if (inner.isEmpty()) {
1688 this->drawRRect(outer, paint);
1689 return;
1690 }
1691
1692 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001693 // be able to return ...
1694 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001695 //
1696 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001697 if (!outer.getBounds().contains(inner.getBounds())) {
1698 return;
1699 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001700
1701 this->onDrawDRRect(outer, inner, paint);
1702}
1703
reed41af9662015-01-05 07:49:08 -08001704void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001705 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001706 this->onDrawPaint(paint);
1707}
1708
1709void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001710 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001711 // To avoid redundant logic in our culling code and various backends, we always sort rects
1712 // before passing them along.
1713 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001714}
1715
msarettdca352e2016-08-26 06:37:45 -07001716void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001717 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001718 if (region.isEmpty()) {
1719 return;
1720 }
1721
1722 if (region.isRect()) {
1723 return this->drawIRect(region.getBounds(), paint);
1724 }
1725
1726 this->onDrawRegion(region, paint);
1727}
1728
reed41af9662015-01-05 07:49:08 -08001729void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001730 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001731 // To avoid redundant logic in our culling code and various backends, we always sort rects
1732 // before passing them along.
1733 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001734}
1735
1736void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001737 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001738 this->onDrawRRect(rrect, paint);
1739}
1740
1741void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001742 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001743 this->onDrawPoints(mode, count, pts, paint);
1744}
1745
Mike Reede88a1cb2017-03-17 09:50:46 -04001746void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1747 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001748 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001749 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001750 this->onDrawVerticesObject(vertices.get(), mode, paint);
1751}
1752
1753void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001754 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001755 RETURN_ON_NULL(vertices);
1756 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001757}
1758
1759void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001760 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001761 this->onDrawPath(path, paint);
1762}
1763
reeda85d4d02015-05-06 12:56:48 -07001764void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001765 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001766 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001767 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001768}
1769
reede47829b2015-08-06 10:02:53 -07001770void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1771 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001772 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001773 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001774 if (dst.isEmpty() || src.isEmpty()) {
1775 return;
1776 }
1777 this->onDrawImageRect(image, &src, dst, paint, constraint);
1778}
reed41af9662015-01-05 07:49:08 -08001779
reed84984ef2015-07-17 07:09:43 -07001780void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1781 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001782 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001783 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001784}
1785
reede47829b2015-08-06 10:02:53 -07001786void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1787 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001788 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001789 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1790 constraint);
1791}
reede47829b2015-08-06 10:02:53 -07001792
reed4c21dc52015-06-25 12:32:03 -07001793void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1794 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001795 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001796 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001797 if (dst.isEmpty()) {
1798 return;
1799 }
msarett552bca92016-08-03 06:53:26 -07001800 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1801 this->onDrawImageNine(image, center, dst, paint);
1802 } else {
reede47829b2015-08-06 10:02:53 -07001803 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001804 }
reed4c21dc52015-06-25 12:32:03 -07001805}
1806
msarett16882062016-08-16 09:31:08 -07001807void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1808 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001809 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001810 RETURN_ON_NULL(image);
1811 if (dst.isEmpty()) {
1812 return;
1813 }
msarett71df2d72016-09-30 12:41:42 -07001814
1815 SkIRect bounds;
1816 Lattice latticePlusBounds = lattice;
1817 if (!latticePlusBounds.fBounds) {
1818 bounds = SkIRect::MakeWH(image->width(), image->height());
1819 latticePlusBounds.fBounds = &bounds;
1820 }
1821
1822 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1823 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001824 } else {
1825 this->drawImageRect(image, dst, paint);
1826 }
1827}
1828
reed41af9662015-01-05 07:49:08 -08001829void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001830 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001831 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001832 return;
1833 }
reed41af9662015-01-05 07:49:08 -08001834 this->onDrawBitmap(bitmap, dx, dy, paint);
1835}
1836
reede47829b2015-08-06 10:02:53 -07001837void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001838 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001839 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001840 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001841 return;
1842 }
reede47829b2015-08-06 10:02:53 -07001843 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001844}
1845
reed84984ef2015-07-17 07:09:43 -07001846void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1847 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001848 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001849}
1850
reede47829b2015-08-06 10:02:53 -07001851void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1852 SrcRectConstraint constraint) {
1853 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1854 constraint);
1855}
reede47829b2015-08-06 10:02:53 -07001856
reed41af9662015-01-05 07:49:08 -08001857void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1858 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001859 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001860 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001861 return;
1862 }
msarett552bca92016-08-03 06:53:26 -07001863 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1864 this->onDrawBitmapNine(bitmap, center, dst, paint);
1865 } else {
reeda5517e22015-07-14 10:54:12 -07001866 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001867 }
reed41af9662015-01-05 07:49:08 -08001868}
1869
msarettc573a402016-08-02 08:05:56 -07001870void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1871 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001872 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001873 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001874 return;
1875 }
msarett71df2d72016-09-30 12:41:42 -07001876
1877 SkIRect bounds;
1878 Lattice latticePlusBounds = lattice;
1879 if (!latticePlusBounds.fBounds) {
1880 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1881 latticePlusBounds.fBounds = &bounds;
1882 }
1883
1884 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1885 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001886 } else {
msarett16882062016-08-16 09:31:08 -07001887 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001888 }
msarettc573a402016-08-02 08:05:56 -07001889}
1890
reed71c3c762015-06-24 10:29:17 -07001891void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001892 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001893 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001894 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001895 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001896 if (count <= 0) {
1897 return;
1898 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001899 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001900 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001901 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001902}
1903
reedf70b5312016-03-04 16:36:20 -08001904void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001905 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001906 if (key) {
1907 this->onDrawAnnotation(rect, key, value);
1908 }
1909}
1910
reede47829b2015-08-06 10:02:53 -07001911void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1912 const SkPaint* paint, SrcRectConstraint constraint) {
1913 if (src) {
1914 this->drawImageRect(image, *src, dst, paint, constraint);
1915 } else {
1916 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1917 dst, paint, constraint);
1918 }
1919}
1920void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1921 const SkPaint* paint, SrcRectConstraint constraint) {
1922 if (src) {
1923 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1924 } else {
1925 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1926 dst, paint, constraint);
1927 }
1928}
1929
Mike Reed4204da22017-05-17 08:53:36 -04001930void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001931 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001932 this->onDrawShadowRec(path, rec);
1933}
1934
1935void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1936 SkPaint paint;
1937 const SkRect& pathBounds = path.getBounds();
1938
1939 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1940 while (iter.next()) {
1941 iter.fDevice->drawShadow(path, rec);
1942 }
1943 LOOPER_END
1944}
1945
reed@android.com8a1c16f2008-12-17 15:59:43 +00001946//////////////////////////////////////////////////////////////////////////////
1947// These are the virtual drawing methods
1948//////////////////////////////////////////////////////////////////////////////
1949
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001950void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001951 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001952 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1953 }
1954}
1955
reed41af9662015-01-05 07:49:08 -08001956void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001957 this->internalDrawPaint(paint);
1958}
1959
1960void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001961 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001962
1963 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001964 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001965 }
1966
reed@google.com4e2b3d32011-04-07 14:18:59 +00001967 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001968}
1969
reed41af9662015-01-05 07:49:08 -08001970void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1971 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001972 if ((long)count <= 0) {
1973 return;
1974 }
1975
Mike Reed822128b2017-02-28 16:41:03 -05001976 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001977 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001978 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001979 // special-case 2 points (common for drawing a single line)
1980 if (2 == count) {
1981 r.set(pts[0], pts[1]);
1982 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001983 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001984 }
Mike Reed822128b2017-02-28 16:41:03 -05001985 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001986 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1987 return;
1988 }
1989 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001990 }
reed@google.coma584aed2012-05-16 14:06:02 +00001991
halcanary96fcdcc2015-08-27 07:41:13 -07001992 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001993
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001994 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001995
reed@android.com8a1c16f2008-12-17 15:59:43 +00001996 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001997 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998 }
reed@google.com4b226022011-01-11 18:32:13 +00001999
reed@google.com4e2b3d32011-04-07 14:18:59 +00002000 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002001}
2002
reed4a167172016-08-18 17:15:25 -07002003static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2004 return ((intptr_t)paint.getImageFilter() |
2005#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2006 (intptr_t)canvas->getDrawFilter() |
2007#endif
2008 (intptr_t)paint.getLooper() ) != 0;
2009}
2010
reed41af9662015-01-05 07:49:08 -08002011void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002012 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002013 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002014 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002015 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002016 return;
2017 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018 }
reed@google.com4b226022011-01-11 18:32:13 +00002019
reed4a167172016-08-18 17:15:25 -07002020 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002021 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002022
reed4a167172016-08-18 17:15:25 -07002023 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002024 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002025 }
2026
2027 LOOPER_END
2028 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002029 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002030 SkDrawIter iter(this);
2031 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002032 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002033 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002034 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002035}
2036
msarett44df6512016-08-25 13:54:30 -07002037void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002038 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002039 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002040 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002041 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2042 return;
2043 }
msarett44df6512016-08-25 13:54:30 -07002044 }
2045
Mike Reed822128b2017-02-28 16:41:03 -05002046 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002047
2048 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002049 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002050 }
2051
2052 LOOPER_END
2053}
2054
reed41af9662015-01-05 07:49:08 -08002055void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002056 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002057 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002058 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002059 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002060 return;
2061 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002062 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002063
Mike Reed822128b2017-02-28 16:41:03 -05002064 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002065
2066 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002067 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002068 }
2069
2070 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002071}
2072
bsalomonac3aa242016-08-19 11:25:19 -07002073void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2074 SkScalar sweepAngle, bool useCenter,
2075 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002076 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002077 if (paint.canComputeFastBounds()) {
2078 SkRect storage;
2079 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002080 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002081 return;
2082 }
bsalomonac3aa242016-08-19 11:25:19 -07002083 }
2084
Mike Reed822128b2017-02-28 16:41:03 -05002085 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002086
2087 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002088 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002089 }
2090
2091 LOOPER_END
2092}
2093
reed41af9662015-01-05 07:49:08 -08002094void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002095 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002096 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002097 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2098 return;
2099 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002100 }
2101
2102 if (rrect.isRect()) {
2103 // call the non-virtual version
2104 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002105 return;
2106 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002107 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002108 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2109 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002110 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002111
Mike Reed822128b2017-02-28 16:41:03 -05002112 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002113
2114 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002115 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002116 }
2117
2118 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002119}
2120
Mike Reed822128b2017-02-28 16:41:03 -05002121void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002122 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002123 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002124 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2125 return;
2126 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002127 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002128
Mike Reed822128b2017-02-28 16:41:03 -05002129 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002130
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002131 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002132 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002133 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002134
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002135 LOOPER_END
2136}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002137
reed41af9662015-01-05 07:49:08 -08002138void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002139 if (!path.isFinite()) {
2140 return;
2141 }
2142
Mike Reed822128b2017-02-28 16:41:03 -05002143 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002144 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002145 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002146 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2147 return;
2148 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002149 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002150
Mike Reed822128b2017-02-28 16:41:03 -05002151 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002152 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002153 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002154 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002155 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002156 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002157
Mike Reed822128b2017-02-28 16:41:03 -05002158 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002159
2160 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002161 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002162 }
2163
reed@google.com4e2b3d32011-04-07 14:18:59 +00002164 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002165}
2166
reed262a71b2015-12-05 13:07:27 -08002167bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002168 if (!paint.getImageFilter()) {
2169 return false;
2170 }
2171
2172 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002173 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002174 return false;
2175 }
2176
2177 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2178 // Once we can filter and the filter will return a result larger than itself, we should be
2179 // able to remove this constraint.
2180 // skbug.com/4526
2181 //
2182 SkPoint pt;
2183 ctm.mapXY(x, y, &pt);
2184 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2185 return ir.contains(fMCRec->fRasterClip.getBounds());
2186}
2187
reeda85d4d02015-05-06 12:56:48 -07002188void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07002189 SkRect bounds = SkRect::MakeXYWH(x, y,
2190 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002191 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002192 SkRect tmp = bounds;
2193 if (paint) {
2194 paint->computeFastBounds(tmp, &tmp);
2195 }
2196 if (this->quickReject(tmp)) {
2197 return;
2198 }
reeda85d4d02015-05-06 12:56:48 -07002199 }
halcanary9d524f22016-03-29 09:03:52 -07002200
reeda85d4d02015-05-06 12:56:48 -07002201 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002202 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002203 paint = lazy.init();
2204 }
reed262a71b2015-12-05 13:07:27 -08002205
reeda2217ef2016-07-20 06:04:34 -07002206 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002207 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2208 *paint);
2209 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002210 special = this->getDevice()->makeSpecial(image);
2211 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002212 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002213 }
2214 }
2215
reed262a71b2015-12-05 13:07:27 -08002216 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2217
reeda85d4d02015-05-06 12:56:48 -07002218 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002219 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002220 if (special) {
2221 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002222 iter.fDevice->ctm().mapXY(x, y, &pt);
2223 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002224 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002225 SkScalarRoundToInt(pt.fY), pnt,
2226 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002227 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002228 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002229 }
reeda85d4d02015-05-06 12:56:48 -07002230 }
halcanary9d524f22016-03-29 09:03:52 -07002231
reeda85d4d02015-05-06 12:56:48 -07002232 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002233}
2234
reed41af9662015-01-05 07:49:08 -08002235void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002236 const SkPaint* paint, SrcRectConstraint constraint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002237 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002238 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002239 if (paint) {
2240 paint->computeFastBounds(dst, &storage);
2241 }
2242 if (this->quickReject(storage)) {
2243 return;
2244 }
reeda85d4d02015-05-06 12:56:48 -07002245 }
2246 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002247 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002248 paint = lazy.init();
2249 }
halcanary9d524f22016-03-29 09:03:52 -07002250
senorblancoc41e7e12015-12-07 12:51:30 -08002251 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002252 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002253
reeda85d4d02015-05-06 12:56:48 -07002254 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002255 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002256 }
halcanary9d524f22016-03-29 09:03:52 -07002257
reeda85d4d02015-05-06 12:56:48 -07002258 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002259}
2260
reed41af9662015-01-05 07:49:08 -08002261void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002262 SkDEBUGCODE(bitmap.validate();)
2263
reed33366972015-10-08 09:22:02 -07002264 if (bitmap.drawsNothing()) {
2265 return;
2266 }
2267
2268 SkLazyPaint lazy;
2269 if (nullptr == paint) {
2270 paint = lazy.init();
2271 }
2272
Mike Reed822128b2017-02-28 16:41:03 -05002273 SkRect bounds;
2274 bitmap.getBounds(&bounds);
2275 bounds.offset(x, y);
2276 bool canFastBounds = paint->canComputeFastBounds();
2277 if (canFastBounds) {
2278 SkRect storage;
2279 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002280 return;
2281 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002282 }
reed@google.com4b226022011-01-11 18:32:13 +00002283
reeda2217ef2016-07-20 06:04:34 -07002284 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002285 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2286 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002287 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002288 special = this->getDevice()->makeSpecial(bitmap);
2289 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002290 drawAsSprite = false;
2291 }
2292 }
2293
Mike Reed822128b2017-02-28 16:41:03 -05002294 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002295
2296 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002297 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002298 if (special) {
reed262a71b2015-12-05 13:07:27 -08002299 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002300 iter.fDevice->ctm().mapXY(x, y, &pt);
2301 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002302 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002303 SkScalarRoundToInt(pt.fY), pnt,
2304 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002305 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002306 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002307 }
reed33366972015-10-08 09:22:02 -07002308 }
msarettfbfa2582016-08-12 08:29:08 -07002309
reed33366972015-10-08 09:22:02 -07002310 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002311}
2312
reed@google.com9987ec32011-09-07 11:57:52 +00002313// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002314void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002315 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002316 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002317 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318 return;
2319 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002320
halcanary96fcdcc2015-08-27 07:41:13 -07002321 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002322 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002323 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2324 return;
2325 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002326 }
reed@google.com3d608122011-11-21 15:16:16 +00002327
reed@google.com33535f32012-09-25 15:37:50 +00002328 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002329 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002330 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002331 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002332
senorblancoc41e7e12015-12-07 12:51:30 -08002333 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002334 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002335
reed@google.com33535f32012-09-25 15:37:50 +00002336 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002337 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002338 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002339
reed@google.com33535f32012-09-25 15:37:50 +00002340 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002341}
2342
reed41af9662015-01-05 07:49:08 -08002343void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002344 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002345 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002346 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002347}
2348
reed4c21dc52015-06-25 12:32:03 -07002349void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2350 const SkPaint* paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002351 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002352 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002353 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2354 return;
2355 }
reed@google.com3d608122011-11-21 15:16:16 +00002356 }
halcanary9d524f22016-03-29 09:03:52 -07002357
reed4c21dc52015-06-25 12:32:03 -07002358 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002359 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002360 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002361 }
halcanary9d524f22016-03-29 09:03:52 -07002362
senorblancoc41e7e12015-12-07 12:51:30 -08002363 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002364
reed4c21dc52015-06-25 12:32:03 -07002365 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002366 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002367 }
halcanary9d524f22016-03-29 09:03:52 -07002368
reed4c21dc52015-06-25 12:32:03 -07002369 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002370}
2371
reed41af9662015-01-05 07:49:08 -08002372void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2373 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002374 SkDEBUGCODE(bitmap.validate();)
2375
halcanary96fcdcc2015-08-27 07:41:13 -07002376 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002377 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002378 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2379 return;
2380 }
reed4c21dc52015-06-25 12:32:03 -07002381 }
halcanary9d524f22016-03-29 09:03:52 -07002382
reed4c21dc52015-06-25 12:32:03 -07002383 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002384 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002385 paint = lazy.init();
2386 }
halcanary9d524f22016-03-29 09:03:52 -07002387
senorblancoc41e7e12015-12-07 12:51:30 -08002388 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002389
reed4c21dc52015-06-25 12:32:03 -07002390 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002391 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002392 }
halcanary9d524f22016-03-29 09:03:52 -07002393
reed4c21dc52015-06-25 12:32:03 -07002394 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002395}
2396
msarett16882062016-08-16 09:31:08 -07002397void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2398 const SkPaint* paint) {
2399 if (nullptr == paint || paint->canComputeFastBounds()) {
2400 SkRect storage;
2401 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2402 return;
2403 }
2404 }
2405
2406 SkLazyPaint lazy;
2407 if (nullptr == paint) {
2408 paint = lazy.init();
2409 }
2410
2411 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2412
2413 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002414 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002415 }
2416
2417 LOOPER_END
2418}
2419
2420void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2421 const SkRect& dst, const SkPaint* paint) {
2422 if (nullptr == paint || paint->canComputeFastBounds()) {
2423 SkRect storage;
2424 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2425 return;
2426 }
2427 }
2428
2429 SkLazyPaint lazy;
2430 if (nullptr == paint) {
2431 paint = lazy.init();
2432 }
2433
2434 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2435
2436 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002437 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002438 }
2439
2440 LOOPER_END
2441}
2442
reed@google.comf67e4cf2011-03-15 20:56:58 +00002443class SkDeviceFilteredPaint {
2444public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002445 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002446 uint32_t filteredFlags = device->filterTextFlags(paint);
2447 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002448 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002449 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002450 fPaint = newPaint;
2451 } else {
2452 fPaint = &paint;
2453 }
2454 }
2455
reed@google.comf67e4cf2011-03-15 20:56:58 +00002456 const SkPaint& paint() const { return *fPaint; }
2457
2458private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002459 const SkPaint* fPaint;
2460 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002461};
2462
reed@google.come0d9ce82014-04-23 04:00:17 +00002463void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2464 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002465 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466
2467 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002468 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002469 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002470 }
2471
reed@google.com4e2b3d32011-04-07 14:18:59 +00002472 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473}
2474
reed@google.come0d9ce82014-04-23 04:00:17 +00002475void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2476 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002477 SkPoint textOffset = SkPoint::Make(0, 0);
2478
halcanary96fcdcc2015-08-27 07:41:13 -07002479 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002480
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002482 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002483 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002484 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002485 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002486
reed@google.com4e2b3d32011-04-07 14:18:59 +00002487 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488}
2489
reed@google.come0d9ce82014-04-23 04:00:17 +00002490void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2491 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002492
2493 SkPoint textOffset = SkPoint::Make(0, constY);
2494
halcanary96fcdcc2015-08-27 07:41:13 -07002495 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002496
reed@android.com8a1c16f2008-12-17 15:59:43 +00002497 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002498 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002499 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002500 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002501 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002502
reed@google.com4e2b3d32011-04-07 14:18:59 +00002503 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002504}
2505
reed@google.come0d9ce82014-04-23 04:00:17 +00002506void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2507 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002508 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002509
reed@android.com8a1c16f2008-12-17 15:59:43 +00002510 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002511 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002512 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002513 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002514
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002515 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002516}
2517
reed45561a02016-07-07 12:47:17 -07002518void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2519 const SkRect* cullRect, const SkPaint& paint) {
2520 if (cullRect && this->quickReject(*cullRect)) {
2521 return;
2522 }
2523
2524 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2525
2526 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002527 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002528 }
2529
2530 LOOPER_END
2531}
2532
fmalita00d5c2c2014-08-21 08:53:26 -07002533void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2534 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002535
fmalita85d5eb92015-03-04 11:20:12 -08002536 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002537 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002538 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002539 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002540 SkRect tmp;
2541 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2542 return;
2543 }
2544 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002545 }
2546
fmalita024f9962015-03-03 19:08:17 -08002547 // We cannot filter in the looper as we normally do, because the paint is
2548 // incomplete at this point (text-related attributes are embedded within blob run paints).
2549 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002550 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002551
fmalita85d5eb92015-03-04 11:20:12 -08002552 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002553
fmalitaaa1b9122014-08-28 14:32:24 -07002554 while (iter.next()) {
2555 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002556 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002557 }
2558
fmalitaaa1b9122014-08-28 14:32:24 -07002559 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002560
2561 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002562}
2563
Cary Clark2a475ea2017-04-28 15:35:12 -04002564void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2565 this->drawText(string.c_str(), string.size(), x, y, paint);
2566}
2567
reed@google.come0d9ce82014-04-23 04:00:17 +00002568// These will become non-virtual, so they always call the (virtual) onDraw... method
2569void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2570 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002571 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002572 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002573 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002574 this->onDrawText(text, byteLength, x, y, paint);
2575 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002576}
2577void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2578 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002579 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002580 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002581 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002582 this->onDrawPosText(text, byteLength, pos, paint);
2583 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002584}
2585void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2586 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002587 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002588 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002589 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002590 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2591 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002592}
2593void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2594 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002595 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002596 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002597 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002598 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2599 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002600}
reed45561a02016-07-07 12:47:17 -07002601void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2602 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002603 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002604 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002605 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002606 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2607 }
2608}
fmalita00d5c2c2014-08-21 08:53:26 -07002609void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2610 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002611 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002612 RETURN_ON_NULL(blob);
reede3b38ce2016-01-08 09:18:44 -08002613 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002614}
reed@google.come0d9ce82014-04-23 04:00:17 +00002615
Mike Reede88a1cb2017-03-17 09:50:46 -04002616void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2617 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002618 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2619
2620 while (iter.next()) {
2621 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002622 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002623 }
2624
2625 LOOPER_END
2626}
2627
dandovb3c9d1c2014-08-12 08:34:29 -07002628void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002629 const SkPoint texCoords[4], SkBlendMode bmode,
2630 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002631 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002632 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002633 return;
2634 }
mtklein6cfa73a2014-08-13 13:33:49 -07002635
Mike Reedfaba3712016-11-03 14:45:31 -04002636 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002637}
2638
2639void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002640 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002641 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002642 // Since a patch is always within the convex hull of the control points, we discard it when its
2643 // bounding rectangle is completely outside the current clip.
2644 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002645 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002646 if (this->quickReject(bounds)) {
2647 return;
2648 }
mtklein6cfa73a2014-08-13 13:33:49 -07002649
Mike Reed435071e2017-05-23 11:22:56 -04002650 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2651
halcanary96fcdcc2015-08-27 07:41:13 -07002652 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002653
dandovecfff212014-08-04 10:02:00 -07002654 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002655 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002656 }
mtklein6cfa73a2014-08-13 13:33:49 -07002657
dandovecfff212014-08-04 10:02:00 -07002658 LOOPER_END
2659}
2660
reeda8db7282015-07-07 10:22:31 -07002661void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002662#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002663 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002664#endif
reede3b38ce2016-01-08 09:18:44 -08002665 RETURN_ON_NULL(dr);
2666 if (x || y) {
2667 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2668 this->onDrawDrawable(dr, &matrix);
2669 } else {
2670 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002671 }
2672}
2673
reeda8db7282015-07-07 10:22:31 -07002674void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002675#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002676 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002677#endif
reede3b38ce2016-01-08 09:18:44 -08002678 RETURN_ON_NULL(dr);
2679 if (matrix && matrix->isIdentity()) {
2680 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002681 }
reede3b38ce2016-01-08 09:18:44 -08002682 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002683}
2684
2685void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002686 // drawable bounds are no longer reliable (e.g. android displaylist)
2687 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002688 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002689}
2690
reed71c3c762015-06-24 10:29:17 -07002691void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002692 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002693 const SkRect* cull, const SkPaint* paint) {
2694 if (cull && this->quickReject(*cull)) {
2695 return;
2696 }
2697
2698 SkPaint pnt;
2699 if (paint) {
2700 pnt = *paint;
2701 }
halcanary9d524f22016-03-29 09:03:52 -07002702
halcanary96fcdcc2015-08-27 07:41:13 -07002703 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002704 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002705 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002706 }
2707 LOOPER_END
2708}
2709
reedf70b5312016-03-04 16:36:20 -08002710void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2711 SkASSERT(key);
2712
2713 SkPaint paint;
2714 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2715 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002716 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002717 }
2718 LOOPER_END
2719}
2720
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721//////////////////////////////////////////////////////////////////////////////
2722// These methods are NOT virtual, and therefore must call back into virtual
2723// methods, rather than actually drawing themselves.
2724//////////////////////////////////////////////////////////////////////////////
2725
reed374772b2016-10-05 17:33:02 -07002726void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002729 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730 this->drawPaint(paint);
2731}
2732
2733void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002734 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2736}
2737
Mike Reed3661bc92017-02-22 13:21:42 -05002738void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002739 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740 pts[0].set(x0, y0);
2741 pts[1].set(x1, y1);
2742 this->drawPoints(kLines_PointMode, 2, pts, paint);
2743}
2744
Mike Reed3661bc92017-02-22 13:21:42 -05002745void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002746 if (radius < 0) {
2747 radius = 0;
2748 }
2749
2750 SkRect r;
2751 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002752 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753}
2754
2755void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2756 const SkPaint& paint) {
2757 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002758 SkRRect rrect;
2759 rrect.setRectXY(r, rx, ry);
2760 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002761 } else {
2762 this->drawRect(r, paint);
2763 }
2764}
2765
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2767 SkScalar sweepAngle, bool useCenter,
2768 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002769 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002770 if (oval.isEmpty() || !sweepAngle) {
2771 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772 }
bsalomon21af9ca2016-08-25 12:29:23 -07002773 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774}
2775
2776void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2777 const SkPath& path, SkScalar hOffset,
2778 SkScalar vOffset, const SkPaint& paint) {
2779 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002780
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 matrix.setTranslate(hOffset, vOffset);
2782 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2783}
2784
reed@android.comf76bacf2009-05-13 14:00:33 +00002785///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002786
2787/**
2788 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2789 * against the playback cost of recursing into the subpicture to get at its actual ops.
2790 *
2791 * For now we pick a conservatively small value, though measurement (and other heuristics like
2792 * the type of ops contained) may justify changing this value.
2793 */
2794#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002795
reedd5fa1a42014-08-09 11:08:05 -07002796void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002797 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002798 RETURN_ON_NULL(picture);
2799
reede3b38ce2016-01-08 09:18:44 -08002800 if (matrix && matrix->isIdentity()) {
2801 matrix = nullptr;
2802 }
2803 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2804 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2805 picture->playback(this);
2806 } else {
2807 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002808 }
2809}
robertphillips9b14f262014-06-04 05:40:44 -07002810
reedd5fa1a42014-08-09 11:08:05 -07002811void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2812 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002813 if (!paint || paint->canComputeFastBounds()) {
2814 SkRect bounds = picture->cullRect();
2815 if (paint) {
2816 paint->computeFastBounds(bounds, &bounds);
2817 }
2818 if (matrix) {
2819 matrix->mapRect(&bounds);
2820 }
2821 if (this->quickReject(bounds)) {
2822 return;
2823 }
2824 }
2825
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002826 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002827 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828}
2829
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830///////////////////////////////////////////////////////////////////////////////
2831///////////////////////////////////////////////////////////////////////////////
2832
reed3aafe112016-08-18 12:45:34 -07002833SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002834 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002835
2836 SkASSERT(canvas);
2837
reed3aafe112016-08-18 12:45:34 -07002838 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839 fDone = !fImpl->next();
2840}
2841
2842SkCanvas::LayerIter::~LayerIter() {
2843 fImpl->~SkDrawIter();
2844}
2845
2846void SkCanvas::LayerIter::next() {
2847 fDone = !fImpl->next();
2848}
2849
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002850SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002851 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002852}
2853
2854const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002855 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002856}
2857
2858const SkPaint& SkCanvas::LayerIter::paint() const {
2859 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002860 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002861 paint = &fDefaultPaint;
2862 }
2863 return *paint;
2864}
2865
Mike Reeda1361362017-03-07 09:37:29 -05002866void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2867 return fImpl->fDevice->onAsRgnClip(rgn);
2868}
2869
reed@android.com8a1c16f2008-12-17 15:59:43 +00002870int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2871int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002872
2873///////////////////////////////////////////////////////////////////////////////
2874
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002875static bool supported_for_raster_canvas(const SkImageInfo& info) {
2876 switch (info.alphaType()) {
2877 case kPremul_SkAlphaType:
2878 case kOpaque_SkAlphaType:
2879 break;
2880 default:
2881 return false;
2882 }
2883
2884 switch (info.colorType()) {
2885 case kAlpha_8_SkColorType:
2886 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002887 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002888 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002889 break;
2890 default:
2891 return false;
2892 }
2893
2894 return true;
2895}
2896
Mike Reed5df49342016-11-12 08:06:55 -06002897std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002898 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002899 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002900 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002901 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002902
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002903 SkBitmap bitmap;
2904 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002905 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002906 }
Mike Reed12f77342017-11-08 11:19:52 -05002907
2908 return props ?
2909 skstd::make_unique<SkCanvas>(bitmap, *props) :
2910 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002911}
reedd5fa1a42014-08-09 11:08:05 -07002912
2913///////////////////////////////////////////////////////////////////////////////
2914
Florin Malitaee424ac2016-12-01 12:47:59 -05002915SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2916 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2917
Florin Malita439ace92016-12-02 12:05:41 -05002918SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2919 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2920
Florin Malitaee424ac2016-12-01 12:47:59 -05002921SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2922 (void)this->INHERITED::getSaveLayerStrategy(rec);
2923 return kNoLayer_SaveLayerStrategy;
2924}
2925
2926///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002927
reed73603f32016-09-20 08:42:38 -07002928static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2929static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2930static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2931static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2932static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2933static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002934
2935///////////////////////////////////////////////////////////////////////////////////////////////////
2936
2937SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2938 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002939 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002940 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2941 SkIPoint origin = dev->getOrigin();
2942 SkMatrix ctm = this->getTotalMatrix();
2943 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2944
2945 SkIRect clip = fMCRec->fRasterClip.getBounds();
2946 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002947 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002948 clip.setEmpty();
2949 }
2950
2951 fAllocator->updateHandle(handle, ctm, clip);
2952 return handle;
2953 }
2954 return nullptr;
2955}
2956
2957static bool install(SkBitmap* bm, const SkImageInfo& info,
2958 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002959 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002960}
2961
2962SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2963 SkBitmap* bm) {
2964 SkRasterHandleAllocator::Rec rec;
2965 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2966 return nullptr;
2967 }
2968 return rec.fHandle;
2969}
2970
2971std::unique_ptr<SkCanvas>
2972SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2973 const SkImageInfo& info, const Rec* rec) {
2974 if (!alloc || !supported_for_raster_canvas(info)) {
2975 return nullptr;
2976 }
2977
2978 SkBitmap bm;
2979 Handle hndl;
2980
2981 if (rec) {
2982 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2983 } else {
2984 hndl = alloc->allocBitmap(info, &bm);
2985 }
2986 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2987}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002988
2989///////////////////////////////////////////////////////////////////////////////////////////////////
2990
2991