blob: dab5be499a62bd6f462b673ac90724b70c03fd85 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Florin Malitaab244f02017-05-03 19:16:58 +000023#include "SkLights.h"
Mike Reed5df49342016-11-12 08:06:55 -060024#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080025#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000026#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050027#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070028#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070029#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070030#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000031#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040036#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000037#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070038#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000039#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000040#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080041#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070042#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080045#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050046#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070047
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050049#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050050#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051
reede3b38ce2016-01-08 09:18:44 -080052#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
53
Mike Reed139e5e02017-03-08 11:29:33 -050054class SkNoPixelsDevice : public SkBaseDevice {
55public:
56 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
57 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
Mike Reed566e53c2017-03-10 10:49:45 -050058 {
Mike Reede393a622017-03-10 16:35:25 -050059 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
60 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050061 }
Mike Reed139e5e02017-03-08 11:29:33 -050062
63 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050064 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050065 this->privateResize(bounds.width(), bounds.height());
66 }
67
68protected:
69 // We don't track the clip at all (for performance), but we have to respond to some queries.
70 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
71 void onSave() override {}
72 void onRestore() override {}
73 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
74 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
75 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
76 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
77 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
78 bool onClipIsAA() const override { return false; }
79 void onAsRgnClip(SkRegion* rgn) const override {
80 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
81 }
82 ClipType onGetClipType() const override {
83 return kRect_ClipType;
84 }
85
86 void drawPaint(const SkPaint& paint) override {}
87 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
88 void drawRect(const SkRect&, const SkPaint&) override {}
89 void drawOval(const SkRect&, const SkPaint&) override {}
90 void drawRRect(const SkRRect&, const SkPaint&) override {}
91 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
Hal Canaryb9642382017-06-27 09:58:56 -040092 void drawBitmap(const SkBitmap&, SkScalar x, SkScalar y, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -050093 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
94 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
95 SkCanvas::SrcRectConstraint) override {}
96 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
97 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
98 const SkPaint&) override {}
99 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
Mike Reed2f6b5a42017-03-19 15:04:17 -0400100 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -0500101
102private:
103 typedef SkBaseDevice INHERITED;
104};
105
106///////////////////////////////////////////////////////////////////////////////////////////////////
107
reedc83a2972015-07-16 07:40:45 -0700108/*
109 * Return true if the drawing this rect would hit every pixels in the canvas.
110 *
111 * Returns false if
112 * - rect does not contain the canvas' bounds
113 * - paint is not fill
114 * - paint would blur or otherwise change the coverage of the rect
115 */
116bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
117 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700118 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
119 (int)kNone_ShaderOverrideOpacity,
120 "need_matching_enums0");
121 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
122 (int)kOpaque_ShaderOverrideOpacity,
123 "need_matching_enums1");
124 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
125 (int)kNotOpaque_ShaderOverrideOpacity,
126 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700127
128 const SkISize size = this->getBaseLayerSize();
129 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500130
131 // if we're clipped at all, we can't overwrite the entire surface
132 {
133 SkBaseDevice* base = this->getDevice();
134 SkBaseDevice* top = this->getTopDevice();
135 if (base != top) {
136 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
137 }
138 if (!base->clipIsWideOpen()) {
139 return false;
140 }
reedc83a2972015-07-16 07:40:45 -0700141 }
142
143 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700144 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700145 return false; // conservative
146 }
halcanaryc5769b22016-08-10 07:13:21 -0700147
148 SkRect devRect;
149 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
150 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700151 return false;
152 }
153 }
154
155 if (paint) {
156 SkPaint::Style paintStyle = paint->getStyle();
157 if (!(paintStyle == SkPaint::kFill_Style ||
158 paintStyle == SkPaint::kStrokeAndFill_Style)) {
159 return false;
160 }
161 if (paint->getMaskFilter() || paint->getLooper()
162 || paint->getPathEffect() || paint->getImageFilter()) {
163 return false; // conservative
164 }
165 }
166 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
167}
168
169///////////////////////////////////////////////////////////////////////////////////////////////////
170
reedd990e2f2014-12-22 11:58:30 -0800171static bool gIgnoreSaveLayerBounds;
172void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
173 gIgnoreSaveLayerBounds = ignore;
174}
175bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
176 return gIgnoreSaveLayerBounds;
177}
178
reed0acf1b42014-12-22 16:12:38 -0800179static bool gTreatSpriteAsBitmap;
180void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
181 gTreatSpriteAsBitmap = spriteAsBitmap;
182}
183bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
184 return gTreatSpriteAsBitmap;
185}
186
reed@google.comda17f752012-08-16 18:27:05 +0000187// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188//#define SK_TRACE_SAVERESTORE
189
190#ifdef SK_TRACE_SAVERESTORE
191 static int gLayerCounter;
192 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
193 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
194
195 static int gRecCounter;
196 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
197 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
198
199 static int gCanvasCounter;
200 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
201 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
202#else
203 #define inc_layer()
204 #define dec_layer()
205 #define inc_rec()
206 #define dec_rec()
207 #define inc_canvas()
208 #define dec_canvas()
209#endif
210
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000211typedef SkTLazy<SkPaint> SkLazyPaint;
212
reedc83a2972015-07-16 07:40:45 -0700213void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000214 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700215 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
216 ? SkSurface::kDiscard_ContentChangeMode
217 : SkSurface::kRetain_ContentChangeMode);
218 }
219}
220
221void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
222 ShaderOverrideOpacity overrideOpacity) {
223 if (fSurfaceBase) {
224 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
225 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
226 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
227 // and therefore we don't care which mode we're in.
228 //
229 if (fSurfaceBase->outstandingImageSnapshot()) {
230 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
231 mode = SkSurface::kDiscard_ContentChangeMode;
232 }
233 }
234 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000235 }
236}
237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000240/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 The clip/matrix/proc are fields that reflect the top of the save/restore
242 stack. Whenever the canvas changes, it marks a dirty flag, and then before
243 these are used (assuming we're not on a layer) we rebuild these cache
244 values: they reflect the top of the save stack, but translated and clipped
245 by the device's XY offset and bitmap-bounds.
246*/
247struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400248 DeviceCM* fNext;
249 sk_sp<SkBaseDevice> fDevice;
250 SkRasterClip fClip;
251 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
252 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400253 sk_sp<SkImage> fClipImage;
254 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255
Florin Malita53f77bd2017-04-28 13:48:37 -0400256 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000257 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700258 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400259 , fDevice(std::move(device))
260 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700261 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000262 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400263 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400264 {}
reed@google.com4b226022011-01-11 18:32:13 +0000265
mtkleinfeaadee2015-04-08 11:25:48 -0700266 void reset(const SkIRect& bounds) {
267 SkASSERT(!fPaint);
268 SkASSERT(!fNext);
269 SkASSERT(fDevice);
270 fClip.setRect(bounds);
271 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272};
273
274/* This is the record we keep for each save/restore level in the stack.
275 Since a level optionally copies the matrix and/or stack, we have pointers
276 for these fields. If the value is copied for this level, the copy is
277 stored in the ...Storage field, and the pointer points to that. If the
278 value is not copied for this level, we ignore ...Storage, and just point
279 at the corresponding value in the previous level in the stack.
280*/
281class SkCanvas::MCRec {
282public:
reed1f836ee2014-07-07 07:49:34 -0700283 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700284 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 /* If there are any layers in the stack, this points to the top-most
286 one that is at or below this level in the stack (so we know what
287 bitmap/device to draw into from this level. This value is NOT
288 reference counted, since the real owner is either our fLayer field,
289 or a previous one in a lower level.)
290 */
Mike Reeda1361362017-03-07 09:37:29 -0500291 DeviceCM* fTopLayer;
292 SkConservativeClip fRasterClip;
293 SkMatrix fMatrix;
294 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295
Mike Reeda1361362017-03-07 09:37:29 -0500296 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700297 fFilter = nullptr;
298 fLayer = nullptr;
299 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800300 fMatrix.reset();
301 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700302
reedd9544982014-09-09 18:46:22 -0700303 // don't bother initializing fNext
304 inc_rec();
305 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400306 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700307 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700308 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700309 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800310 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700311
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312 // don't bother initializing fNext
313 inc_rec();
314 }
315 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000316 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700317 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000318 dec_rec();
319 }
mtkleinfeaadee2015-04-08 11:25:48 -0700320
321 void reset(const SkIRect& bounds) {
322 SkASSERT(fLayer);
323 SkASSERT(fDeferredSaveCount == 0);
324
325 fMatrix.reset();
326 fRasterClip.setRect(bounds);
327 fLayer->reset(bounds);
328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329};
330
Mike Reeda1361362017-03-07 09:37:29 -0500331class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332public:
Mike Reeda1361362017-03-07 09:37:29 -0500333 SkDrawIter(SkCanvas* canvas)
334 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
335 {}
reed@google.com4b226022011-01-11 18:32:13 +0000336
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000338 const DeviceCM* rec = fCurrLayer;
339 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400340 fDevice = rec->fDevice.get();
341 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700343 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 return true;
345 }
346 return false;
347 }
reed@google.com4b226022011-01-11 18:32:13 +0000348
reed@google.com6f8f2922011-03-04 22:27:10 +0000349 int getX() const { return fDevice->getOrigin().x(); }
350 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000352
Mike Reed99330ba2017-02-22 11:01:08 -0500353 SkBaseDevice* fDevice;
354
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 const DeviceCM* fCurrLayer;
357 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358};
359
Florin Malita713b8ef2017-04-28 10:57:24 -0400360#define FOR_EACH_TOP_DEVICE( code ) \
361 do { \
362 DeviceCM* layer = fMCRec->fTopLayer; \
363 while (layer) { \
364 SkBaseDevice* device = layer->fDevice.get(); \
365 if (device) { \
366 code; \
367 } \
368 layer = layer->fNext; \
369 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500370 } while (0)
371
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372/////////////////////////////////////////////////////////////////////////////
373
reeddbc3cef2015-04-29 12:18:57 -0700374static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
375 return lazy->isValid() ? lazy->get() : lazy->set(orig);
376}
377
378/**
379 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700380 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700381 */
reedd053ce92016-03-22 10:17:23 -0700382static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700383 SkImageFilter* imgf = paint.getImageFilter();
384 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700385 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700386 }
387
reedd053ce92016-03-22 10:17:23 -0700388 SkColorFilter* imgCFPtr;
389 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700390 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700391 }
reedd053ce92016-03-22 10:17:23 -0700392 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700393
394 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700395 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700396 // there is no existing paint colorfilter, so we can just return the imagefilter's
397 return imgCF;
398 }
399
400 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
401 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700402 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700403}
404
senorblanco87e066e2015-10-28 11:23:36 -0700405/**
406 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
407 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
408 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
409 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
410 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
411 * conservative "effective" bounds based on the settings in the paint... with one exception. This
412 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
413 * deliberately ignored.
414 */
415static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
416 const SkRect& rawBounds,
417 SkRect* storage) {
418 SkPaint tmpUnfiltered(paint);
419 tmpUnfiltered.setImageFilter(nullptr);
420 if (tmpUnfiltered.canComputeFastBounds()) {
421 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
422 } else {
423 return rawBounds;
424 }
425}
426
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427class AutoDrawLooper {
428public:
senorblanco87e066e2015-10-28 11:23:36 -0700429 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
430 // paint. It's used to determine the size of the offscreen layer for filters.
431 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700432 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700433 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000434 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800435#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800437#else
438 fFilter = nullptr;
439#endif
reed4a8126e2014-09-22 07:29:03 -0700440 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000441 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700442 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000443 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444
reedd053ce92016-03-22 10:17:23 -0700445 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700446 if (simplifiedCF) {
447 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700448 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700449 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700450 fPaint = paint;
451 }
452
453 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700454 /**
455 * We implement ImageFilters for a given draw by creating a layer, then applying the
456 * imagefilter to the pixels of that layer (its backing surface/image), and then
457 * we call restore() to xfer that layer to the main canvas.
458 *
459 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
460 * 2. Generate the src pixels:
461 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
462 * return (fPaint). We then draw the primitive (using srcover) into a cleared
463 * buffer/surface.
464 * 3. Restore the layer created in #1
465 * The imagefilter is passed the buffer/surface from the layer (now filled with the
466 * src pixels of the primitive). It returns a new "filtered" buffer, which we
467 * draw onto the previous layer using the xfermode from the original paint.
468 */
reed@google.com8926b162012-03-23 15:36:36 +0000469 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500470 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700471 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700472 SkRect storage;
473 if (rawBounds) {
474 // Make rawBounds include all paint outsets except for those due to image filters.
475 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
476 }
reedbfd5f172016-01-07 11:28:08 -0800477 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700478 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700479 fTempLayerForImageFilter = true;
480 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000481 }
482
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000483 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500484 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000485 fIsSimple = false;
486 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700487 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000488 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700489 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000490 }
491 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000492
reed@android.com8a1c16f2008-12-17 15:59:43 +0000493 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700494 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000495 fCanvas->internalRestore();
496 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000497 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000499
reed@google.com4e2b3d32011-04-07 14:18:59 +0000500 const SkPaint& paint() const {
501 SkASSERT(fPaint);
502 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000504
reed@google.com129ec222012-05-15 13:24:09 +0000505 bool next(SkDrawFilter::Type drawType) {
506 if (fDone) {
507 return false;
508 } else if (fIsSimple) {
509 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000510 return !fPaint->nothingToDraw();
511 } else {
512 return this->doNext(drawType);
513 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500517 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700518 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000519 SkCanvas* fCanvas;
520 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000521 SkDrawFilter* fFilter;
522 const SkPaint* fPaint;
523 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700524 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000525 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000526 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000527 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400528 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000529
530 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000531};
532
reed@google.com129ec222012-05-15 13:24:09 +0000533bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700534 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000535 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700536 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000537
reeddbc3cef2015-04-29 12:18:57 -0700538 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
539 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000540
reed5c476fb2015-04-20 08:04:21 -0700541 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700542 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700543 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000544 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000545
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000546 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000547 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000548 return false;
549 }
550 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000551 if (!fFilter->filter(paint, drawType)) {
552 fDone = true;
553 return false;
554 }
halcanary96fcdcc2015-08-27 07:41:13 -0700555 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000556 // no looper means we only draw once
557 fDone = true;
558 }
559 }
560 fPaint = paint;
561
562 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000563 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000564 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000565 }
566
567 // call this after any possible paint modifiers
568 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700569 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000570 return false;
571 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000572 return true;
573}
574
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575////////// macros to place around the internal draw calls //////////////////
576
reed3aafe112016-08-18 12:45:34 -0700577#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
578 this->predrawNotify(); \
579 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
580 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800581 SkDrawIter iter(this);
582
583
reed@google.com8926b162012-03-23 15:36:36 +0000584#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000585 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700586 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000587 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000588 SkDrawIter iter(this);
589
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000590#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000591 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700592 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000593 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000594 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000595
reedc83a2972015-07-16 07:40:45 -0700596#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
597 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700598 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700599 while (looper.next(type)) { \
600 SkDrawIter iter(this);
601
reed@google.com4e2b3d32011-04-07 14:18:59 +0000602#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603
604////////////////////////////////////////////////////////////////////////////
605
msarettfbfa2582016-08-12 08:29:08 -0700606static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
607 if (bounds.isEmpty()) {
608 return SkRect::MakeEmpty();
609 }
610
611 // Expand bounds out by 1 in case we are anti-aliasing. We store the
612 // bounds as floats to enable a faster quick reject implementation.
613 SkRect dst;
614 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
615 return dst;
616}
617
mtkleinfeaadee2015-04-08 11:25:48 -0700618void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
619 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700620 fMCRec->reset(bounds);
621
622 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500623 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400624 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700625 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700626 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700627}
628
reedd9544982014-09-09 18:46:22 -0700629SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800630 if (device && device->forceConservativeRasterClip()) {
631 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
632 }
reed42b73eb2015-11-20 13:42:42 -0800633
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000634 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800635 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700636 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637
638 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500639 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500640 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700641 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642
reeda499f902015-05-01 09:34:31 -0700643 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
644 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400645 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700646
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648
halcanary96fcdcc2015-08-27 07:41:13 -0700649 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000650
reedf92c8662014-08-18 08:02:43 -0700651 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700652 // The root device and the canvas should always have the same pixel geometry
653 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800654 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700655 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500656
Mike Reedc42a1cd2017-02-14 14:25:14 -0500657 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700658 }
msarettfbfa2582016-08-12 08:29:08 -0700659
reedf92c8662014-08-18 08:02:43 -0700660 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661}
662
reed@google.comcde92112011-07-06 20:00:52 +0000663SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000664 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700665 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000666{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000667 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000668
halcanary96fcdcc2015-08-27 07:41:13 -0700669 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000670}
671
reed96a857e2015-01-25 10:33:58 -0800672SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000673 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800674 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000675{
676 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700677
Mike Reed566e53c2017-03-10 10:49:45 -0500678 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700679 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700680}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000681
reed78e27682014-11-19 08:04:34 -0800682SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700683 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700684 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700685{
686 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700687
Mike Reed566e53c2017-03-10 10:49:45 -0500688 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
689 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700690}
691
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000692SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000693 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700694 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000695{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700697
reedd9544982014-09-09 18:46:22 -0700698 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699}
700
robertphillipsfcf78292015-06-19 11:49:52 -0700701SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
702 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700703 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700704{
705 inc_canvas();
706
707 this->init(device, flags);
708}
709
reed4a8126e2014-09-22 07:29:03 -0700710SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700711 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700712 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700713{
714 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700715
Hal Canary704cd322016-11-07 14:13:52 -0500716 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
717 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700718}
reed29c857d2014-09-21 10:25:07 -0700719
Mike Reed356f7c22017-01-10 11:58:39 -0500720SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
721 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700722 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
723 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500724 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700725{
726 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700727
Mike Reed356f7c22017-01-10 11:58:39 -0500728 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500729 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000730}
731
Mike Reed356f7c22017-01-10 11:58:39 -0500732SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
733
Matt Sarett31f99ce2017-04-11 08:46:01 -0400734#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
735SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
736 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
737 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
738 , fAllocator(nullptr)
739{
740 inc_canvas();
741
742 SkBitmap tmp(bitmap);
743 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
744 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
745 this->init(device.get(), kDefault_InitFlags);
746}
747#endif
748
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749SkCanvas::~SkCanvas() {
750 // free up the contents of our deque
751 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000752
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753 this->internalRestore(); // restore the last, since we're going away
754
halcanary385fe4d2015-08-26 13:07:48 -0700755 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000756
reed@android.com8a1c16f2008-12-17 15:59:43 +0000757 dec_canvas();
758}
759
fmalita53d9f1c2016-01-25 06:23:54 -0800760#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761SkDrawFilter* SkCanvas::getDrawFilter() const {
762 return fMCRec->fFilter;
763}
764
765SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700766 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
768 return filter;
769}
fmalita77650002016-01-21 18:47:11 -0800770#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000772SkMetaData& SkCanvas::getMetaData() {
773 // metadata users are rare, so we lazily allocate it. If that changes we
774 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700775 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000776 fMetaData = new SkMetaData;
777 }
778 return *fMetaData;
779}
780
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781///////////////////////////////////////////////////////////////////////////////
782
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000783void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700784 this->onFlush();
785}
786
787void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000788 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000789 if (device) {
790 device->flush();
791 }
792}
793
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000794SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000795 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000796 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
797}
798
senorblancoafc7cce2016-02-02 18:44:15 -0800799SkIRect SkCanvas::getTopLayerBounds() const {
800 SkBaseDevice* d = this->getTopDevice();
801 if (!d) {
802 return SkIRect::MakeEmpty();
803 }
804 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
805}
806
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000807SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000809 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400811 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812}
813
Florin Malita0ed3b642017-01-13 16:56:38 +0000814SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400815 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000816}
817
reed96472de2014-12-10 09:53:42 -0800818bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000819 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000820 if (!device) {
821 return false;
822 }
mtkleinf0f14112014-12-12 08:46:25 -0800823
Matt Sarett03dd6d52017-01-23 12:15:09 -0500824 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000825}
826
Mike Reed12e946b2017-04-17 10:53:29 -0400827bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
828 return pm.addr() && this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y);
829}
830
831bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
832 SkPixmap pm;
833 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
834}
835
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000836bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400837 SkPixmap pm;
838 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700839 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000840 }
841 return false;
842}
843
Matt Sarett03dd6d52017-01-23 12:15:09 -0500844bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000845 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000846 SkBaseDevice* device = this->getDevice();
847 if (!device) {
848 return false;
849 }
850
Matt Sarett03dd6d52017-01-23 12:15:09 -0500851 // This check gives us an early out and prevents generation ID churn on the surface.
852 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
853 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
854 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
855 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000856 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000857
Matt Sarett03dd6d52017-01-23 12:15:09 -0500858 // Tell our owning surface to bump its generation ID.
859 const bool completeOverwrite =
860 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700861 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700862
Matt Sarett03dd6d52017-01-23 12:15:09 -0500863 // This can still fail, most notably in the case of a invalid color type or alpha type
864 // conversion. We could pull those checks into this function and avoid the unnecessary
865 // generation ID bump. But then we would be performing those checks twice, since they
866 // are also necessary at the bitmap/pixmap entry points.
867 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000868}
reed@google.com51df9e32010-12-23 19:29:18 +0000869
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870//////////////////////////////////////////////////////////////////////////////
871
reed2ff1fce2014-12-11 07:07:37 -0800872void SkCanvas::checkForDeferredSave() {
873 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800874 this->doSave();
875 }
876}
877
reedf0090cb2014-11-26 08:55:51 -0800878int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800879#ifdef SK_DEBUG
880 int count = 0;
881 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
882 for (;;) {
883 const MCRec* rec = (const MCRec*)iter.next();
884 if (!rec) {
885 break;
886 }
887 count += 1 + rec->fDeferredSaveCount;
888 }
889 SkASSERT(count == fSaveCount);
890#endif
891 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800892}
893
894int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800895 fSaveCount += 1;
896 fMCRec->fDeferredSaveCount += 1;
897 return this->getSaveCount() - 1; // return our prev value
898}
899
900void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800901 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700902
903 SkASSERT(fMCRec->fDeferredSaveCount > 0);
904 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800905 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800906}
907
908void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800909 if (fMCRec->fDeferredSaveCount > 0) {
910 SkASSERT(fSaveCount > 1);
911 fSaveCount -= 1;
912 fMCRec->fDeferredSaveCount -= 1;
913 } else {
914 // check for underflow
915 if (fMCStack.count() > 1) {
916 this->willRestore();
917 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700918 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800919 this->internalRestore();
920 this->didRestore();
921 }
reedf0090cb2014-11-26 08:55:51 -0800922 }
923}
924
925void SkCanvas::restoreToCount(int count) {
926 // sanity check
927 if (count < 1) {
928 count = 1;
929 }
mtkleinf0f14112014-12-12 08:46:25 -0800930
reedf0090cb2014-11-26 08:55:51 -0800931 int n = this->getSaveCount() - count;
932 for (int i = 0; i < n; ++i) {
933 this->restore();
934 }
935}
936
reed2ff1fce2014-12-11 07:07:37 -0800937void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000938 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700939 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000940 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000941
Mike Reedc42a1cd2017-02-14 14:25:14 -0500942 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000943}
944
reed4960eee2015-12-18 07:09:18 -0800945bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800946 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000947}
948
reed4960eee2015-12-18 07:09:18 -0800949bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700950 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500951 SkIRect clipBounds = this->getDeviceClipBounds();
952 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000953 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000954 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000955
reed96e657d2015-03-10 17:30:07 -0700956 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
957
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000958 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700959 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800960 if (bounds && !imageFilter->canComputeFastBounds()) {
961 bounds = nullptr;
962 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000963 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000964 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700965 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000967
reed96e657d2015-03-10 17:30:07 -0700968 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969 r.roundOut(&ir);
970 // early exit if the layer's bounds are clipped out
971 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800972 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500973 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700974 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700975 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000976 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000977 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 }
979 } else { // no user bounds, so just use the clip
980 ir = clipBounds;
981 }
reed180aec42015-03-11 10:39:04 -0700982 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000983
reed4960eee2015-12-18 07:09:18 -0800984 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700985 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700986 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700987 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000988 }
989
990 if (intersection) {
991 *intersection = ir;
992 }
993 return true;
994}
995
reed4960eee2015-12-18 07:09:18 -0800996
reed4960eee2015-12-18 07:09:18 -0800997int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
998 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000999}
1000
reed70ee31b2015-12-10 13:44:45 -08001001int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001002 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1003}
1004
1005int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001006 SkTCopyOnFirstWrite<SaveLayerRec> rec(origRec);
reed4960eee2015-12-18 07:09:18 -08001007 if (gIgnoreSaveLayerBounds) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001008 rec.writable()->fBounds = nullptr;
reed4960eee2015-12-18 07:09:18 -08001009 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001010
1011 SaveLayerStrategy strategy = this->getSaveLayerStrategy(*rec);
reed4960eee2015-12-18 07:09:18 -08001012 fSaveCount += 1;
Florin Malita53f77bd2017-04-28 13:48:37 -04001013 this->internalSaveLayer(*rec, strategy);
reed4960eee2015-12-18 07:09:18 -08001014 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001015}
1016
reeda2217ef2016-07-20 06:04:34 -07001017void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001018 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001019 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001020 SkDraw draw;
1021 SkRasterClip rc;
1022 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1023 if (!dst->accessPixels(&draw.fDst)) {
1024 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001025 }
reeda2217ef2016-07-20 06:04:34 -07001026 draw.fMatrix = &SkMatrix::I();
1027 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001028
1029 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001030 if (filter) {
1031 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1032 }
reeda2217ef2016-07-20 06:04:34 -07001033
Mike Reedc42a1cd2017-02-14 14:25:14 -05001034 int x = src->getOrigin().x() - dstOrigin.x();
1035 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001036 auto special = src->snapSpecial();
1037 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001038 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -07001039 }
robertphillips7354a4b2015-12-16 05:08:27 -08001040}
reed70ee31b2015-12-10 13:44:45 -08001041
reed129ed1c2016-02-22 06:42:31 -08001042static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1043 const SkPaint* paint) {
1044 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1045 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001046 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001047 const bool hasImageFilter = paint && paint->getImageFilter();
1048
1049 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1050 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1051 // force to L32
1052 return SkImageInfo::MakeN32(w, h, alphaType);
1053 } else {
1054 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001055 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001056 }
1057}
1058
reed4960eee2015-12-18 07:09:18 -08001059void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1060 const SkRect* bounds = rec.fBounds;
1061 const SkPaint* paint = rec.fPaint;
1062 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1063
reed8c30a812016-04-20 16:36:51 -07001064 SkLazyPaint lazyP;
1065 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1066 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001067 SkMatrix remainder;
1068 SkSize scale;
1069 /*
1070 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1071 * but they do handle scaling. To accommodate this, we do the following:
1072 *
1073 * 1. Stash off the current CTM
1074 * 2. Decompose the CTM into SCALE and REMAINDER
1075 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1076 * contains the REMAINDER
1077 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1078 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1079 * of the original imagefilter, and draw that (via drawSprite)
1080 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1081 *
1082 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1083 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1084 */
reed96a04f32016-04-25 09:25:15 -07001085 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001086 stashedMatrix.decomposeScale(&scale, &remainder))
1087 {
1088 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1089 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1090 SkPaint* p = lazyP.set(*paint);
1091 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1092 SkFilterQuality::kLow_SkFilterQuality,
1093 sk_ref_sp(imageFilter)));
1094 imageFilter = p->getImageFilter();
1095 paint = p;
1096 }
reed8c30a812016-04-20 16:36:51 -07001097
junov@chromium.orga907ac32012-02-24 21:54:07 +00001098 // do this before we create the layer. We don't call the public save() since
1099 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001100 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001101
junov@chromium.orga907ac32012-02-24 21:54:07 +00001102 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001103 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001104 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001105 }
1106
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001107 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1108 // the clipRectBounds() call above?
1109 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001110 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001111 }
1112
reed4960eee2015-12-18 07:09:18 -08001113 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001114 SkPixelGeometry geo = fProps.pixelGeometry();
1115 if (paint) {
reed76033be2015-03-14 10:54:31 -07001116 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001117 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001118 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001119 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001120 }
1121 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001122
robertphillips5139e502016-07-19 05:10:40 -07001123 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001124 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001125 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001126 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001127 }
reedb2db8982014-11-13 12:41:02 -08001128
robertphillips5139e502016-07-19 05:10:40 -07001129 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001130 paint);
1131
Hal Canary704cd322016-11-07 14:13:52 -05001132 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001133 {
reed70ee31b2015-12-10 13:44:45 -08001134 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001135 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001136 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001137 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001138 preserveLCDText,
1139 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001140 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1141 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001142 return;
reed61f501f2015-04-29 08:34:00 -07001143 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001144 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001145 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001146
Mike Reedb43a3e02017-02-11 10:18:58 -05001147 // only have a "next" if this new layer doesn't affect the clip (rare)
1148 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149 fMCRec->fLayer = layer;
1150 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001151
Mike Reedc61abee2017-02-28 17:45:27 -05001152 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001153 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001154 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001155 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001156
Mike Reedc42a1cd2017-02-14 14:25:14 -05001157 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1158
1159 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1160 if (layer->fNext) {
1161 // need to punch a hole in the previous device, so we don't draw there, given that
1162 // the new top-layer will allow drawing to happen "below" it.
1163 SkRegion hole(ir);
1164 do {
1165 layer = layer->fNext;
1166 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1167 } while (layer->fNext);
1168 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001169}
1170
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001171int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001172 if (0xFF == alpha) {
1173 return this->saveLayer(bounds, nullptr);
1174 } else {
1175 SkPaint tmpPaint;
1176 tmpPaint.setAlpha(alpha);
1177 return this->saveLayer(bounds, &tmpPaint);
1178 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001179}
1180
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181void SkCanvas::internalRestore() {
1182 SkASSERT(fMCStack.count() != 0);
1183
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001184 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001185 DeviceCM* layer = fMCRec->fLayer; // may be null
1186 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001187 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188
1189 // now do the normal restore()
1190 fMCRec->~MCRec(); // balanced in save()
1191 fMCStack.pop_back();
1192 fMCRec = (MCRec*)fMCStack.back();
1193
Mike Reedc42a1cd2017-02-14 14:25:14 -05001194 if (fMCRec) {
1195 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1196 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001197
reed@android.com8a1c16f2008-12-17 15:59:43 +00001198 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1199 since if we're being recorded, we don't want to record this (the
1200 recorder will have already recorded the restore).
1201 */
bsalomon49f085d2014-09-05 13:34:00 -07001202 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001203 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001204 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001205 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001206 layer->fPaint.get(),
1207 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001208 // restore what we smashed in internalSaveLayer
1209 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001210 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001211 delete layer;
reedb679ca82015-04-07 04:40:48 -07001212 } else {
1213 // we're at the root
reeda499f902015-05-01 09:34:31 -07001214 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001215 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001216 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001218 }
msarettfbfa2582016-08-12 08:29:08 -07001219
1220 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001221 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001222 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1223 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224}
1225
reede8f30622016-03-23 18:59:25 -07001226sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001227 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001228 props = &fProps;
1229 }
1230 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001231}
1232
reede8f30622016-03-23 18:59:25 -07001233sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001234 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001235 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001236}
1237
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001238SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001239 return this->onImageInfo();
1240}
1241
1242SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001243 SkBaseDevice* dev = this->getDevice();
1244 if (dev) {
1245 return dev->imageInfo();
1246 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001247 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001248 }
1249}
1250
brianosman898235c2016-04-06 07:38:23 -07001251bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001252 return this->onGetProps(props);
1253}
1254
1255bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001256 SkBaseDevice* dev = this->getDevice();
1257 if (dev) {
1258 if (props) {
1259 *props = fProps;
1260 }
1261 return true;
1262 } else {
1263 return false;
1264 }
1265}
1266
reed6ceeebd2016-03-09 14:26:26 -08001267bool SkCanvas::peekPixels(SkPixmap* pmap) {
1268 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001269}
1270
reed884e97c2015-05-26 11:31:54 -07001271bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001272 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001273 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001274}
1275
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001276void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001277 SkPixmap pmap;
1278 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001279 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001280 }
1281 if (info) {
1282 *info = pmap.info();
1283 }
1284 if (rowBytes) {
1285 *rowBytes = pmap.rowBytes();
1286 }
1287 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001288 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001289 }
reed884e97c2015-05-26 11:31:54 -07001290 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001291}
1292
reed884e97c2015-05-26 11:31:54 -07001293bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001294 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001295 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001296}
1297
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299
Florin Malita53f77bd2017-04-28 13:48:37 -04001300void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1301 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001303 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001304 paint = &tmp;
1305 }
reed@google.com4b226022011-01-11 18:32:13 +00001306
reed@google.com8926b162012-03-23 15:36:36 +00001307 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001308
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001310 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001311 paint = &looper.paint();
1312 SkImageFilter* filter = paint->getImageFilter();
1313 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001314 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001315 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1316 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001317 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1318 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001319 }
reed@google.com76dd2772012-01-05 21:15:07 +00001320 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001321 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001322 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323 }
reeda2217ef2016-07-20 06:04:34 -07001324
reed@google.com4e2b3d32011-04-07 14:18:59 +00001325 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326}
1327
reed32704672015-12-16 08:27:10 -08001328/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001329
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001330void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001331 if (dx || dy) {
1332 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001333 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001334
reedfe69b502016-09-12 06:31:48 -07001335 // Translate shouldn't affect the is-scale-translateness of the matrix.
1336 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001337
Mike Reedc42a1cd2017-02-14 14:25:14 -05001338 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001339
reedfe69b502016-09-12 06:31:48 -07001340 this->didTranslate(dx,dy);
1341 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342}
1343
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001344void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001345 SkMatrix m;
1346 m.setScale(sx, sy);
1347 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001348}
1349
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001350void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001351 SkMatrix m;
1352 m.setRotate(degrees);
1353 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354}
1355
bungeman7438bfc2016-07-12 15:01:19 -07001356void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1357 SkMatrix m;
1358 m.setRotate(degrees, px, py);
1359 this->concat(m);
1360}
1361
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001362void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001363 SkMatrix m;
1364 m.setSkew(sx, sy);
1365 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001366}
1367
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001368void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001369 if (matrix.isIdentity()) {
1370 return;
1371 }
1372
reed2ff1fce2014-12-11 07:07:37 -08001373 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001374 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001375 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001376
Mike Reed7627fa52017-02-08 10:07:53 -05001377 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001378
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001379 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001380}
1381
reed8c30a812016-04-20 16:36:51 -07001382void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001383 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001384 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001385
Mike Reedc42a1cd2017-02-14 14:25:14 -05001386 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001387}
1388
1389void SkCanvas::setMatrix(const SkMatrix& matrix) {
1390 this->checkForDeferredSave();
1391 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001392 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001393}
1394
reed@android.com8a1c16f2008-12-17 15:59:43 +00001395void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001396 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001397}
1398
1399//////////////////////////////////////////////////////////////////////////////
1400
Mike Reedc1f77742016-12-09 09:00:50 -05001401void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001402 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001403 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1404 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001405}
1406
Mike Reedc1f77742016-12-09 09:00:50 -05001407void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001408 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001409
Mike Reed7627fa52017-02-08 10:07:53 -05001410 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001411
reedc64eff52015-11-21 12:39:45 -08001412 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001413 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1414 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001415 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416}
1417
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001418void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1419 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001420 if (fClipRestrictionRect.isEmpty()) {
1421 // we notify the device, but we *dont* resolve deferred saves (since we're just
1422 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001423 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001424 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001425 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001426 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001427 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001428 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001429 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1430 }
1431}
1432
Mike Reedc1f77742016-12-09 09:00:50 -05001433void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001434 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001435 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001436 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1438 } else {
1439 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001440 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001441}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001442
Mike Reedc1f77742016-12-09 09:00:50 -05001443void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001444 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001445
Brian Salomona3b45d42016-10-03 11:36:16 -04001446 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001447
Mike Reed7627fa52017-02-08 10:07:53 -05001448 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001449
Brian Salomona3b45d42016-10-03 11:36:16 -04001450 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1451 isAA);
1452 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001453}
1454
Mike Reedc1f77742016-12-09 09:00:50 -05001455void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001456 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001457 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001458
1459 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1460 SkRect r;
1461 if (path.isRect(&r)) {
1462 this->onClipRect(r, op, edgeStyle);
1463 return;
1464 }
1465 SkRRect rrect;
1466 if (path.isOval(&r)) {
1467 rrect.setOval(r);
1468 this->onClipRRect(rrect, op, edgeStyle);
1469 return;
1470 }
1471 if (path.isRRect(&rrect)) {
1472 this->onClipRRect(rrect, op, edgeStyle);
1473 return;
1474 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001475 }
robertphillips39f05382015-11-24 09:30:12 -08001476
1477 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001478}
1479
Mike Reedc1f77742016-12-09 09:00:50 -05001480void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001481 AutoValidateClip avc(this);
1482
Brian Salomona3b45d42016-10-03 11:36:16 -04001483 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001484
Mike Reed7627fa52017-02-08 10:07:53 -05001485 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486
Brian Salomona3b45d42016-10-03 11:36:16 -04001487 const SkPath* rasterClipPath = &path;
1488 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001489 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1490 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001491 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001492}
1493
Mike Reedc1f77742016-12-09 09:00:50 -05001494void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001495 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001496 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001497}
1498
Mike Reedc1f77742016-12-09 09:00:50 -05001499void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001500 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001501
reed@google.com5c3d1472011-02-22 19:12:23 +00001502 AutoValidateClip avc(this);
1503
reed73603f32016-09-20 08:42:38 -07001504 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001505 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001506}
1507
reed@google.com819c9212011-02-23 18:56:55 +00001508#ifdef SK_DEBUG
1509void SkCanvas::validateClip() const {
1510 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001511 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001512 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001513 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001514 return;
1515 }
reed@google.com819c9212011-02-23 18:56:55 +00001516}
1517#endif
1518
Mike Reeda1361362017-03-07 09:37:29 -05001519bool SkCanvas::androidFramework_isClipAA() const {
1520 bool containsAA = false;
1521
1522 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1523
1524 return containsAA;
1525}
1526
1527class RgnAccumulator {
1528 SkRegion* fRgn;
1529public:
1530 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1531 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1532 SkIPoint origin = device->getOrigin();
1533 if (origin.x() | origin.y()) {
1534 rgn->translate(origin.x(), origin.y());
1535 }
1536 fRgn->op(*rgn, SkRegion::kUnion_Op);
1537 }
1538};
1539
1540void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1541 RgnAccumulator accum(rgn);
1542 SkRegion tmp;
1543
1544 rgn->setEmpty();
1545 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001546}
1547
reed@google.com5c3d1472011-02-22 19:12:23 +00001548///////////////////////////////////////////////////////////////////////////////
1549
reed@google.com754de5f2014-02-24 19:38:20 +00001550bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001551 return fMCRec->fRasterClip.isEmpty();
1552
1553 // TODO: should we only use the conservative answer in a recording canvas?
1554#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001555 SkBaseDevice* dev = this->getTopDevice();
1556 // if no device we return true
1557 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001558#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001559}
1560
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001561bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001562 SkBaseDevice* dev = this->getTopDevice();
1563 // if no device we return false
1564 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001565}
1566
msarettfbfa2582016-08-12 08:29:08 -07001567static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1568#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1569 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1570 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1571 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1572 return 0xF != _mm_movemask_ps(mask);
1573#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1574 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1575 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1576 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1577 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1578#else
1579 SkRect devRectAsRect;
1580 SkRect devClipAsRect;
1581 devRect.store(&devRectAsRect.fLeft);
1582 devClip.store(&devClipAsRect.fLeft);
1583 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1584#endif
1585}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001586
msarettfbfa2582016-08-12 08:29:08 -07001587// It's important for this function to not be inlined. Otherwise the compiler will share code
1588// between the fast path and the slow path, resulting in two slow paths.
1589static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1590 const SkMatrix& matrix) {
1591 SkRect deviceRect;
1592 matrix.mapRect(&deviceRect, src);
1593 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1594}
1595
1596bool SkCanvas::quickReject(const SkRect& src) const {
1597#ifdef SK_DEBUG
1598 // Verify that fDeviceClipBounds are set properly.
1599 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001600 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001601 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001602 } else {
msarettfbfa2582016-08-12 08:29:08 -07001603 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001604 }
msarettfbfa2582016-08-12 08:29:08 -07001605
msarett9637ea92016-08-18 14:03:30 -07001606 // Verify that fIsScaleTranslate is set properly.
1607 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001608#endif
1609
msarett9637ea92016-08-18 14:03:30 -07001610 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001611 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1612 }
1613
1614 // We inline the implementation of mapScaleTranslate() for the fast path.
1615 float sx = fMCRec->fMatrix.getScaleX();
1616 float sy = fMCRec->fMatrix.getScaleY();
1617 float tx = fMCRec->fMatrix.getTranslateX();
1618 float ty = fMCRec->fMatrix.getTranslateY();
1619 Sk4f scale(sx, sy, sx, sy);
1620 Sk4f trans(tx, ty, tx, ty);
1621
1622 // Apply matrix.
1623 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1624
1625 // Make sure left < right, top < bottom.
1626 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1627 Sk4f min = Sk4f::Min(ltrb, rblt);
1628 Sk4f max = Sk4f::Max(ltrb, rblt);
1629 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1630 // ARM this sequence generates the fastest (a single instruction).
1631 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1632
1633 // Check if the device rect is NaN or outside the clip.
1634 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001635}
1636
reed@google.com3b3e8952012-08-16 20:53:31 +00001637bool SkCanvas::quickReject(const SkPath& path) const {
1638 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001639}
1640
Mike Reed42e8c532017-01-23 14:09:13 -05001641SkRect SkCanvas::onGetLocalClipBounds() const {
1642 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001643 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001644 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001645 }
1646
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001647 SkMatrix inverse;
1648 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001649 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001650 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001651 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652
Mike Reed42e8c532017-01-23 14:09:13 -05001653 SkRect bounds;
1654 SkRect r;
1655 // adjust it outwards in case we are antialiasing
1656 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001657
Mike Reed42e8c532017-01-23 14:09:13 -05001658 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1659 ibounds.fRight + inset, ibounds.fBottom + inset);
1660 inverse.mapRect(&bounds, r);
1661 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662}
1663
Mike Reed42e8c532017-01-23 14:09:13 -05001664SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001665 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001666}
1667
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001669 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001670}
1671
Brian Osman11052242016-10-27 14:47:55 -04001672GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001673 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001674 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001675}
1676
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001677GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001678 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001679 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001680}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001681
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001682void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1683 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001684 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001685 if (outer.isEmpty()) {
1686 return;
1687 }
1688 if (inner.isEmpty()) {
1689 this->drawRRect(outer, paint);
1690 return;
1691 }
1692
1693 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001694 // be able to return ...
1695 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001696 //
1697 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001698 if (!outer.getBounds().contains(inner.getBounds())) {
1699 return;
1700 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001701
1702 this->onDrawDRRect(outer, inner, paint);
1703}
1704
reed41af9662015-01-05 07:49:08 -08001705// These need to stop being virtual -- clients need to override the onDraw... versions
1706
1707void SkCanvas::drawPaint(const SkPaint& paint) {
1708 this->onDrawPaint(paint);
1709}
1710
1711void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001712 // To avoid redundant logic in our culling code and various backends, we always sort rects
1713 // before passing them along.
1714 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001715}
1716
msarettdca352e2016-08-26 06:37:45 -07001717void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1718 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 Osman6e3ce402017-05-17 15:10:18 -04001730 // To avoid redundant logic in our culling code and various backends, we always sort rects
1731 // before passing them along.
1732 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001733}
1734
1735void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1736 this->onDrawRRect(rrect, paint);
1737}
1738
1739void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1740 this->onDrawPoints(mode, count, pts, paint);
1741}
1742
Mike Reede88a1cb2017-03-17 09:50:46 -04001743void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1744 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001745 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001746 this->onDrawVerticesObject(vertices.get(), mode, paint);
1747}
1748
1749void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1750 RETURN_ON_NULL(vertices);
1751 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001752}
1753
1754void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1755 this->onDrawPath(path, paint);
1756}
1757
reeda85d4d02015-05-06 12:56:48 -07001758void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001759 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001760 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001761}
1762
reede47829b2015-08-06 10:02:53 -07001763void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1764 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001765 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001766 if (dst.isEmpty() || src.isEmpty()) {
1767 return;
1768 }
1769 this->onDrawImageRect(image, &src, dst, paint, constraint);
1770}
reed41af9662015-01-05 07:49:08 -08001771
reed84984ef2015-07-17 07:09:43 -07001772void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1773 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001774 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001775 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001776}
1777
reede47829b2015-08-06 10:02:53 -07001778void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1779 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001780 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001781 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1782 constraint);
1783}
reede47829b2015-08-06 10:02:53 -07001784
reed4c21dc52015-06-25 12:32:03 -07001785void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1786 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001787 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001788 if (dst.isEmpty()) {
1789 return;
1790 }
msarett552bca92016-08-03 06:53:26 -07001791 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1792 this->onDrawImageNine(image, center, dst, paint);
1793 } else {
reede47829b2015-08-06 10:02:53 -07001794 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001795 }
reed4c21dc52015-06-25 12:32:03 -07001796}
1797
msarett16882062016-08-16 09:31:08 -07001798void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1799 const SkPaint* paint) {
1800 RETURN_ON_NULL(image);
1801 if (dst.isEmpty()) {
1802 return;
1803 }
msarett71df2d72016-09-30 12:41:42 -07001804
1805 SkIRect bounds;
1806 Lattice latticePlusBounds = lattice;
1807 if (!latticePlusBounds.fBounds) {
1808 bounds = SkIRect::MakeWH(image->width(), image->height());
1809 latticePlusBounds.fBounds = &bounds;
1810 }
1811
1812 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1813 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001814 } else {
1815 this->drawImageRect(image, dst, paint);
1816 }
1817}
1818
reed41af9662015-01-05 07:49:08 -08001819void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001820 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001821 return;
1822 }
reed41af9662015-01-05 07:49:08 -08001823 this->onDrawBitmap(bitmap, dx, dy, paint);
1824}
1825
reede47829b2015-08-06 10:02:53 -07001826void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001827 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001828 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001829 return;
1830 }
reede47829b2015-08-06 10:02:53 -07001831 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001832}
1833
reed84984ef2015-07-17 07:09:43 -07001834void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1835 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001836 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001837}
1838
reede47829b2015-08-06 10:02:53 -07001839void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1840 SrcRectConstraint constraint) {
1841 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1842 constraint);
1843}
reede47829b2015-08-06 10:02:53 -07001844
reed41af9662015-01-05 07:49:08 -08001845void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1846 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001847 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001848 return;
1849 }
msarett552bca92016-08-03 06:53:26 -07001850 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1851 this->onDrawBitmapNine(bitmap, center, dst, paint);
1852 } else {
reeda5517e22015-07-14 10:54:12 -07001853 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001854 }
reed41af9662015-01-05 07:49:08 -08001855}
1856
msarettc573a402016-08-02 08:05:56 -07001857void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1858 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001859 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001860 return;
1861 }
msarett71df2d72016-09-30 12:41:42 -07001862
1863 SkIRect bounds;
1864 Lattice latticePlusBounds = lattice;
1865 if (!latticePlusBounds.fBounds) {
1866 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1867 latticePlusBounds.fBounds = &bounds;
1868 }
1869
1870 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1871 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001872 } else {
msarett16882062016-08-16 09:31:08 -07001873 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001874 }
msarettc573a402016-08-02 08:05:56 -07001875}
1876
reed71c3c762015-06-24 10:29:17 -07001877void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001878 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001879 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001880 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001881 if (count <= 0) {
1882 return;
1883 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001884 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001885 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001886 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001887}
1888
reedf70b5312016-03-04 16:36:20 -08001889void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1890 if (key) {
1891 this->onDrawAnnotation(rect, key, value);
1892 }
1893}
1894
reede47829b2015-08-06 10:02:53 -07001895void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1896 const SkPaint* paint, SrcRectConstraint constraint) {
1897 if (src) {
1898 this->drawImageRect(image, *src, dst, paint, constraint);
1899 } else {
1900 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1901 dst, paint, constraint);
1902 }
1903}
1904void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1905 const SkPaint* paint, SrcRectConstraint constraint) {
1906 if (src) {
1907 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1908 } else {
1909 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1910 dst, paint, constraint);
1911 }
1912}
1913
Mike Reed4204da22017-05-17 08:53:36 -04001914void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
1915 this->onDrawShadowRec(path, rec);
1916}
1917
1918void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1919 SkPaint paint;
1920 const SkRect& pathBounds = path.getBounds();
1921
1922 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1923 while (iter.next()) {
1924 iter.fDevice->drawShadow(path, rec);
1925 }
1926 LOOPER_END
1927}
1928
reed@android.com8a1c16f2008-12-17 15:59:43 +00001929//////////////////////////////////////////////////////////////////////////////
1930// These are the virtual drawing methods
1931//////////////////////////////////////////////////////////////////////////////
1932
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001933void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001934 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001935 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1936 }
1937}
1938
reed41af9662015-01-05 07:49:08 -08001939void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001940 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001941 this->internalDrawPaint(paint);
1942}
1943
1944void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001945 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001946
1947 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001948 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001949 }
1950
reed@google.com4e2b3d32011-04-07 14:18:59 +00001951 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001952}
1953
reed41af9662015-01-05 07:49:08 -08001954void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1955 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001956 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001957 if ((long)count <= 0) {
1958 return;
1959 }
1960
Mike Reed822128b2017-02-28 16:41:03 -05001961 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001962 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001963 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001964 // special-case 2 points (common for drawing a single line)
1965 if (2 == count) {
1966 r.set(pts[0], pts[1]);
1967 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001968 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001969 }
Mike Reed822128b2017-02-28 16:41:03 -05001970 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001971 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1972 return;
1973 }
1974 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001975 }
reed@google.coma584aed2012-05-16 14:06:02 +00001976
halcanary96fcdcc2015-08-27 07:41:13 -07001977 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001978
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001979 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001980
reed@android.com8a1c16f2008-12-17 15:59:43 +00001981 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001982 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001983 }
reed@google.com4b226022011-01-11 18:32:13 +00001984
reed@google.com4e2b3d32011-04-07 14:18:59 +00001985 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001986}
1987
reed4a167172016-08-18 17:15:25 -07001988static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1989 return ((intptr_t)paint.getImageFilter() |
1990#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1991 (intptr_t)canvas->getDrawFilter() |
1992#endif
1993 (intptr_t)paint.getLooper() ) != 0;
1994}
1995
reed41af9662015-01-05 07:49:08 -08001996void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001997 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
Brian Osman6e3ce402017-05-17 15:10:18 -04001998 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002000 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002001 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002002 return;
2003 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004 }
reed@google.com4b226022011-01-11 18:32:13 +00002005
reed4a167172016-08-18 17:15:25 -07002006 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002007 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002008
reed4a167172016-08-18 17:15:25 -07002009 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002010 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002011 }
2012
2013 LOOPER_END
2014 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002015 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002016 SkDrawIter iter(this);
2017 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002018 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002019 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002020 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002021}
2022
msarett44df6512016-08-25 13:54:30 -07002023void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002024 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002025 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002026 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002027 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2028 return;
2029 }
msarett44df6512016-08-25 13:54:30 -07002030 }
2031
Mike Reed822128b2017-02-28 16:41:03 -05002032 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002033
2034 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002035 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002036 }
2037
2038 LOOPER_END
2039}
2040
reed41af9662015-01-05 07:49:08 -08002041void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002042 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
Brian Osman6e3ce402017-05-17 15:10:18 -04002043 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002044 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002045 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002046 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002047 return;
2048 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002049 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002050
Mike Reed822128b2017-02-28 16:41:03 -05002051 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002052
2053 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002054 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002055 }
2056
2057 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002058}
2059
bsalomonac3aa242016-08-19 11:25:19 -07002060void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2061 SkScalar sweepAngle, bool useCenter,
2062 const SkPaint& paint) {
2063 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
Brian Osman6e3ce402017-05-17 15:10:18 -04002064 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002065 if (paint.canComputeFastBounds()) {
2066 SkRect storage;
2067 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002068 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002069 return;
2070 }
bsalomonac3aa242016-08-19 11:25:19 -07002071 }
2072
Mike Reed822128b2017-02-28 16:41:03 -05002073 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002074
2075 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002076 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002077 }
2078
2079 LOOPER_END
2080}
2081
reed41af9662015-01-05 07:49:08 -08002082void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002083 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002084 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002085 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002086 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2087 return;
2088 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002089 }
2090
2091 if (rrect.isRect()) {
2092 // call the non-virtual version
2093 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002094 return;
2095 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002096 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002097 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2098 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002099 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002100
Mike Reed822128b2017-02-28 16:41:03 -05002101 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002102
2103 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002104 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002105 }
2106
2107 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002108}
2109
Mike Reed822128b2017-02-28 16:41:03 -05002110void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002111 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002112 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002113 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2114 return;
2115 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002116 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002117
Mike Reed822128b2017-02-28 16:41:03 -05002118 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002119
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002120 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002121 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002122 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002123
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002124 LOOPER_END
2125}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002126
reed41af9662015-01-05 07:49:08 -08002127void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002128 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002129 if (!path.isFinite()) {
2130 return;
2131 }
2132
Mike Reed822128b2017-02-28 16:41:03 -05002133 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002134 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002135 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002136 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2137 return;
2138 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002139 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002140
Mike Reed822128b2017-02-28 16:41:03 -05002141 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002142 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002143 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002144 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002145 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002146 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002147
Mike Reed822128b2017-02-28 16:41:03 -05002148 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002149
2150 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002151 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002152 }
2153
reed@google.com4e2b3d32011-04-07 14:18:59 +00002154 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002155}
2156
reed262a71b2015-12-05 13:07:27 -08002157bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002158 if (!paint.getImageFilter()) {
2159 return false;
2160 }
2161
2162 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002163 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002164 return false;
2165 }
2166
2167 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2168 // Once we can filter and the filter will return a result larger than itself, we should be
2169 // able to remove this constraint.
2170 // skbug.com/4526
2171 //
2172 SkPoint pt;
2173 ctm.mapXY(x, y, &pt);
2174 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2175 return ir.contains(fMCRec->fRasterClip.getBounds());
2176}
2177
reeda85d4d02015-05-06 12:56:48 -07002178void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002179 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002180 SkRect bounds = SkRect::MakeXYWH(x, y,
2181 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002182 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002183 SkRect tmp = bounds;
2184 if (paint) {
2185 paint->computeFastBounds(tmp, &tmp);
2186 }
2187 if (this->quickReject(tmp)) {
2188 return;
2189 }
reeda85d4d02015-05-06 12:56:48 -07002190 }
halcanary9d524f22016-03-29 09:03:52 -07002191
reeda85d4d02015-05-06 12:56:48 -07002192 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002193 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002194 paint = lazy.init();
2195 }
reed262a71b2015-12-05 13:07:27 -08002196
reeda2217ef2016-07-20 06:04:34 -07002197 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002198 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2199 *paint);
2200 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002201 special = this->getDevice()->makeSpecial(image);
2202 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002203 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002204 }
2205 }
2206
reed262a71b2015-12-05 13:07:27 -08002207 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2208
reeda85d4d02015-05-06 12:56:48 -07002209 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002210 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002211 if (special) {
2212 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002213 iter.fDevice->ctm().mapXY(x, y, &pt);
2214 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002215 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002216 SkScalarRoundToInt(pt.fY), pnt,
2217 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002218 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002219 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002220 }
reeda85d4d02015-05-06 12:56:48 -07002221 }
halcanary9d524f22016-03-29 09:03:52 -07002222
reeda85d4d02015-05-06 12:56:48 -07002223 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002224}
2225
reed41af9662015-01-05 07:49:08 -08002226void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002227 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002228 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002229 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002230 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002231 if (paint) {
2232 paint->computeFastBounds(dst, &storage);
2233 }
2234 if (this->quickReject(storage)) {
2235 return;
2236 }
reeda85d4d02015-05-06 12:56:48 -07002237 }
2238 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002239 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002240 paint = lazy.init();
2241 }
halcanary9d524f22016-03-29 09:03:52 -07002242
senorblancoc41e7e12015-12-07 12:51:30 -08002243 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002244 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002245
reeda85d4d02015-05-06 12:56:48 -07002246 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002247 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002248 }
halcanary9d524f22016-03-29 09:03:52 -07002249
reeda85d4d02015-05-06 12:56:48 -07002250 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002251}
2252
reed41af9662015-01-05 07:49:08 -08002253void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002254 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002255 SkDEBUGCODE(bitmap.validate();)
2256
reed33366972015-10-08 09:22:02 -07002257 if (bitmap.drawsNothing()) {
2258 return;
2259 }
2260
2261 SkLazyPaint lazy;
2262 if (nullptr == paint) {
2263 paint = lazy.init();
2264 }
2265
Mike Reed822128b2017-02-28 16:41:03 -05002266 SkRect bounds;
2267 bitmap.getBounds(&bounds);
2268 bounds.offset(x, y);
2269 bool canFastBounds = paint->canComputeFastBounds();
2270 if (canFastBounds) {
2271 SkRect storage;
2272 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002273 return;
2274 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002275 }
reed@google.com4b226022011-01-11 18:32:13 +00002276
reeda2217ef2016-07-20 06:04:34 -07002277 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002278 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2279 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002280 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002281 special = this->getDevice()->makeSpecial(bitmap);
2282 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002283 drawAsSprite = false;
2284 }
2285 }
2286
Mike Reed822128b2017-02-28 16:41:03 -05002287 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002288
2289 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002290 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002291 if (special) {
reed262a71b2015-12-05 13:07:27 -08002292 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002293 iter.fDevice->ctm().mapXY(x, y, &pt);
2294 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002295 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002296 SkScalarRoundToInt(pt.fY), pnt,
2297 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002298 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002299 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002300 }
reed33366972015-10-08 09:22:02 -07002301 }
msarettfbfa2582016-08-12 08:29:08 -07002302
reed33366972015-10-08 09:22:02 -07002303 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002304}
2305
reed@google.com9987ec32011-09-07 11:57:52 +00002306// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002307void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002308 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002309 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002310 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002311 return;
2312 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002313
halcanary96fcdcc2015-08-27 07:41:13 -07002314 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002315 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002316 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2317 return;
2318 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002319 }
reed@google.com3d608122011-11-21 15:16:16 +00002320
reed@google.com33535f32012-09-25 15:37:50 +00002321 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002322 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002323 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002325
senorblancoc41e7e12015-12-07 12:51:30 -08002326 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002327 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002328
reed@google.com33535f32012-09-25 15:37:50 +00002329 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002330 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002331 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002332
reed@google.com33535f32012-09-25 15:37:50 +00002333 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002334}
2335
reed41af9662015-01-05 07:49:08 -08002336void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002337 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002338 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002339 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002340 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002341}
2342
reed4c21dc52015-06-25 12:32:03 -07002343void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2344 const SkPaint* paint) {
2345 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002346
halcanary96fcdcc2015-08-27 07:41:13 -07002347 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002348 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002349 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2350 return;
2351 }
reed@google.com3d608122011-11-21 15:16:16 +00002352 }
halcanary9d524f22016-03-29 09:03:52 -07002353
reed4c21dc52015-06-25 12:32:03 -07002354 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002355 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002356 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002357 }
halcanary9d524f22016-03-29 09:03:52 -07002358
senorblancoc41e7e12015-12-07 12:51:30 -08002359 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002360
reed4c21dc52015-06-25 12:32:03 -07002361 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002362 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002363 }
halcanary9d524f22016-03-29 09:03:52 -07002364
reed4c21dc52015-06-25 12:32:03 -07002365 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002366}
2367
reed41af9662015-01-05 07:49:08 -08002368void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2369 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002370 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002371 SkDEBUGCODE(bitmap.validate();)
2372
halcanary96fcdcc2015-08-27 07:41:13 -07002373 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002374 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002375 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2376 return;
2377 }
reed4c21dc52015-06-25 12:32:03 -07002378 }
halcanary9d524f22016-03-29 09:03:52 -07002379
reed4c21dc52015-06-25 12:32:03 -07002380 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002381 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002382 paint = lazy.init();
2383 }
halcanary9d524f22016-03-29 09:03:52 -07002384
senorblancoc41e7e12015-12-07 12:51:30 -08002385 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002386
reed4c21dc52015-06-25 12:32:03 -07002387 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002388 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002389 }
halcanary9d524f22016-03-29 09:03:52 -07002390
reed4c21dc52015-06-25 12:32:03 -07002391 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002392}
2393
msarett16882062016-08-16 09:31:08 -07002394void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2395 const SkPaint* paint) {
2396 if (nullptr == paint || paint->canComputeFastBounds()) {
2397 SkRect storage;
2398 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2399 return;
2400 }
2401 }
2402
2403 SkLazyPaint lazy;
2404 if (nullptr == paint) {
2405 paint = lazy.init();
2406 }
2407
2408 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2409
2410 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002411 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002412 }
2413
2414 LOOPER_END
2415}
2416
2417void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2418 const SkRect& dst, const SkPaint* paint) {
2419 if (nullptr == paint || paint->canComputeFastBounds()) {
2420 SkRect storage;
2421 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2422 return;
2423 }
2424 }
2425
2426 SkLazyPaint lazy;
2427 if (nullptr == paint) {
2428 paint = lazy.init();
2429 }
2430
2431 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2432
2433 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002434 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002435 }
2436
2437 LOOPER_END
2438}
2439
reed@google.comf67e4cf2011-03-15 20:56:58 +00002440class SkDeviceFilteredPaint {
2441public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002442 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002443 uint32_t filteredFlags = device->filterTextFlags(paint);
2444 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002445 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002446 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002447 fPaint = newPaint;
2448 } else {
2449 fPaint = &paint;
2450 }
2451 }
2452
reed@google.comf67e4cf2011-03-15 20:56:58 +00002453 const SkPaint& paint() const { return *fPaint; }
2454
2455private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002456 const SkPaint* fPaint;
2457 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002458};
2459
reed@google.come0d9ce82014-04-23 04:00:17 +00002460void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2461 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002462 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002463
2464 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002465 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002466 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002467 }
2468
reed@google.com4e2b3d32011-04-07 14:18:59 +00002469 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002470}
2471
reed@google.come0d9ce82014-04-23 04:00:17 +00002472void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2473 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002474 SkPoint textOffset = SkPoint::Make(0, 0);
2475
halcanary96fcdcc2015-08-27 07:41:13 -07002476 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002477
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002479 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002480 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002481 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002483
reed@google.com4e2b3d32011-04-07 14:18:59 +00002484 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002485}
2486
reed@google.come0d9ce82014-04-23 04:00:17 +00002487void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2488 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002489
2490 SkPoint textOffset = SkPoint::Make(0, constY);
2491
halcanary96fcdcc2015-08-27 07:41:13 -07002492 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002493
reed@android.com8a1c16f2008-12-17 15:59:43 +00002494 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002495 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002496 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002497 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002498 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002499
reed@google.com4e2b3d32011-04-07 14:18:59 +00002500 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002501}
2502
reed@google.come0d9ce82014-04-23 04:00:17 +00002503void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2504 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002505 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002506
reed@android.com8a1c16f2008-12-17 15:59:43 +00002507 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002508 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002509 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002510 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002511
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002512 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002513}
2514
reed45561a02016-07-07 12:47:17 -07002515void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2516 const SkRect* cullRect, const SkPaint& paint) {
2517 if (cullRect && this->quickReject(*cullRect)) {
2518 return;
2519 }
2520
2521 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2522
2523 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002524 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002525 }
2526
2527 LOOPER_END
2528}
2529
fmalita00d5c2c2014-08-21 08:53:26 -07002530void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2531 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002532
fmalita85d5eb92015-03-04 11:20:12 -08002533 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002534 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002535 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002536 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002537 SkRect tmp;
2538 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2539 return;
2540 }
2541 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002542 }
2543
fmalita024f9962015-03-03 19:08:17 -08002544 // We cannot filter in the looper as we normally do, because the paint is
2545 // incomplete at this point (text-related attributes are embedded within blob run paints).
2546 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002547 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002548
fmalita85d5eb92015-03-04 11:20:12 -08002549 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002550
fmalitaaa1b9122014-08-28 14:32:24 -07002551 while (iter.next()) {
2552 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002553 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002554 }
2555
fmalitaaa1b9122014-08-28 14:32:24 -07002556 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002557
2558 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002559}
2560
Cary Clark2a475ea2017-04-28 15:35:12 -04002561void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2562 this->drawText(string.c_str(), string.size(), x, y, paint);
2563}
2564
reed@google.come0d9ce82014-04-23 04:00:17 +00002565// These will become non-virtual, so they always call the (virtual) onDraw... method
2566void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2567 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002568 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002569 if (byteLength) {
2570 this->onDrawText(text, byteLength, x, y, paint);
2571 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002572}
2573void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2574 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002575 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002576 if (byteLength) {
2577 this->onDrawPosText(text, byteLength, pos, paint);
2578 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002579}
2580void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2581 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002582 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002583 if (byteLength) {
2584 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2585 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002586}
2587void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2588 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002589 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002590 if (byteLength) {
2591 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2592 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002593}
reed45561a02016-07-07 12:47:17 -07002594void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2595 const SkRect* cullRect, const SkPaint& paint) {
2596 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2597 if (byteLength) {
2598 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2599 }
2600}
fmalita00d5c2c2014-08-21 08:53:26 -07002601void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2602 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002603 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002604 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002605 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002606}
reed@google.come0d9ce82014-04-23 04:00:17 +00002607
Mike Reede88a1cb2017-03-17 09:50:46 -04002608void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2609 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002610 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2611 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2612
2613 while (iter.next()) {
2614 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002615 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002616 }
2617
2618 LOOPER_END
2619}
2620
dandovb3c9d1c2014-08-12 08:34:29 -07002621void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002622 const SkPoint texCoords[4], SkBlendMode bmode,
2623 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002624 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002625 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002626 return;
2627 }
mtklein6cfa73a2014-08-13 13:33:49 -07002628
Mike Reedfaba3712016-11-03 14:45:31 -04002629 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002630}
2631
2632void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002633 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002634 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002635 // Since a patch is always within the convex hull of the control points, we discard it when its
2636 // bounding rectangle is completely outside the current clip.
2637 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002638 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002639 if (this->quickReject(bounds)) {
2640 return;
2641 }
mtklein6cfa73a2014-08-13 13:33:49 -07002642
Mike Reed435071e2017-05-23 11:22:56 -04002643 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2644
halcanary96fcdcc2015-08-27 07:41:13 -07002645 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002646
dandovecfff212014-08-04 10:02:00 -07002647 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002648 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002649 }
mtklein6cfa73a2014-08-13 13:33:49 -07002650
dandovecfff212014-08-04 10:02:00 -07002651 LOOPER_END
2652}
2653
reeda8db7282015-07-07 10:22:31 -07002654void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002655 RETURN_ON_NULL(dr);
2656 if (x || y) {
2657 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2658 this->onDrawDrawable(dr, &matrix);
2659 } else {
2660 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002661 }
2662}
2663
reeda8db7282015-07-07 10:22:31 -07002664void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002665 RETURN_ON_NULL(dr);
2666 if (matrix && matrix->isIdentity()) {
2667 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002668 }
reede3b38ce2016-01-08 09:18:44 -08002669 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002670}
2671
2672void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002673 // drawable bounds are no longer reliable (e.g. android displaylist)
2674 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002675 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002676}
2677
reed71c3c762015-06-24 10:29:17 -07002678void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002679 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002680 const SkRect* cull, const SkPaint* paint) {
2681 if (cull && this->quickReject(*cull)) {
2682 return;
2683 }
2684
2685 SkPaint pnt;
2686 if (paint) {
2687 pnt = *paint;
2688 }
halcanary9d524f22016-03-29 09:03:52 -07002689
halcanary96fcdcc2015-08-27 07:41:13 -07002690 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002691 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002692 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002693 }
2694 LOOPER_END
2695}
2696
reedf70b5312016-03-04 16:36:20 -08002697void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2698 SkASSERT(key);
2699
2700 SkPaint paint;
2701 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2702 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002703 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002704 }
2705 LOOPER_END
2706}
2707
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708//////////////////////////////////////////////////////////////////////////////
2709// These methods are NOT virtual, and therefore must call back into virtual
2710// methods, rather than actually drawing themselves.
2711//////////////////////////////////////////////////////////////////////////////
2712
reed374772b2016-10-05 17:33:02 -07002713void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002714 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002715 SkPaint paint;
2716
2717 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002718 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002719 this->drawPaint(paint);
2720}
2721
2722void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002723 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002724 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002725 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2726}
2727
Mike Reed3661bc92017-02-22 13:21:42 -05002728void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002729 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002731
reed@android.com8a1c16f2008-12-17 15:59:43 +00002732 pts[0].set(x0, y0);
2733 pts[1].set(x1, y1);
2734 this->drawPoints(kLines_PointMode, 2, pts, paint);
2735}
2736
Mike Reed3661bc92017-02-22 13:21:42 -05002737void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002738 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002739 if (radius < 0) {
2740 radius = 0;
2741 }
2742
2743 SkRect r;
2744 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002745 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002746}
2747
2748void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2749 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002750 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002752 SkRRect rrect;
2753 rrect.setRectXY(r, rx, ry);
2754 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002755 } else {
2756 this->drawRect(r, paint);
2757 }
2758}
2759
reed@android.com8a1c16f2008-12-17 15:59:43 +00002760void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2761 SkScalar sweepAngle, bool useCenter,
2762 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002763 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002764 if (oval.isEmpty() || !sweepAngle) {
2765 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766 }
bsalomon21af9ca2016-08-25 12:29:23 -07002767 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002768}
2769
2770void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2771 const SkPath& path, SkScalar hOffset,
2772 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002773 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002775
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776 matrix.setTranslate(hOffset, vOffset);
2777 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2778}
2779
reed@android.comf76bacf2009-05-13 14:00:33 +00002780///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002781
2782/**
2783 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2784 * against the playback cost of recursing into the subpicture to get at its actual ops.
2785 *
2786 * For now we pick a conservatively small value, though measurement (and other heuristics like
2787 * the type of ops contained) may justify changing this value.
2788 */
2789#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002790
reedd5fa1a42014-08-09 11:08:05 -07002791void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002792 RETURN_ON_NULL(picture);
2793
reed1c2c4412015-04-30 13:09:24 -07002794 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002795 if (matrix && matrix->isIdentity()) {
2796 matrix = nullptr;
2797 }
2798 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2799 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2800 picture->playback(this);
2801 } else {
2802 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002803 }
2804}
robertphillips9b14f262014-06-04 05:40:44 -07002805
reedd5fa1a42014-08-09 11:08:05 -07002806void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2807 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002808 if (!paint || paint->canComputeFastBounds()) {
2809 SkRect bounds = picture->cullRect();
2810 if (paint) {
2811 paint->computeFastBounds(bounds, &bounds);
2812 }
2813 if (matrix) {
2814 matrix->mapRect(&bounds);
2815 }
2816 if (this->quickReject(bounds)) {
2817 return;
2818 }
2819 }
2820
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002821 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002822 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823}
2824
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825///////////////////////////////////////////////////////////////////////////////
2826///////////////////////////////////////////////////////////////////////////////
2827
reed3aafe112016-08-18 12:45:34 -07002828SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002829 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830
2831 SkASSERT(canvas);
2832
reed3aafe112016-08-18 12:45:34 -07002833 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002834 fDone = !fImpl->next();
2835}
2836
2837SkCanvas::LayerIter::~LayerIter() {
2838 fImpl->~SkDrawIter();
2839}
2840
2841void SkCanvas::LayerIter::next() {
2842 fDone = !fImpl->next();
2843}
2844
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002845SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002846 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847}
2848
2849const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002850 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002851}
2852
2853const SkPaint& SkCanvas::LayerIter::paint() const {
2854 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002855 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002856 paint = &fDefaultPaint;
2857 }
2858 return *paint;
2859}
2860
Mike Reeda1361362017-03-07 09:37:29 -05002861void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2862 return fImpl->fDevice->onAsRgnClip(rgn);
2863}
2864
reed@android.com8a1c16f2008-12-17 15:59:43 +00002865int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2866int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002867
2868///////////////////////////////////////////////////////////////////////////////
2869
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002870static bool supported_for_raster_canvas(const SkImageInfo& info) {
2871 switch (info.alphaType()) {
2872 case kPremul_SkAlphaType:
2873 case kOpaque_SkAlphaType:
2874 break;
2875 default:
2876 return false;
2877 }
2878
2879 switch (info.colorType()) {
2880 case kAlpha_8_SkColorType:
2881 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002882 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002883 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002884 break;
2885 default:
2886 return false;
2887 }
2888
2889 return true;
2890}
2891
Mike Reed5df49342016-11-12 08:06:55 -06002892std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
2893 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002894 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002895 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002896 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002897
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002898 SkBitmap bitmap;
2899 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002900 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002901 }
Mike Reed5df49342016-11-12 08:06:55 -06002902 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002903}
reedd5fa1a42014-08-09 11:08:05 -07002904
2905///////////////////////////////////////////////////////////////////////////////
2906
2907SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002908 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002909 : fCanvas(canvas)
2910 , fSaveCount(canvas->getSaveCount())
2911{
bsalomon49f085d2014-09-05 13:34:00 -07002912 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002913 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002914 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002915 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002916 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002917 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002918 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002919 canvas->save();
2920 }
mtklein6cfa73a2014-08-13 13:33:49 -07002921
bsalomon49f085d2014-09-05 13:34:00 -07002922 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002923 canvas->concat(*matrix);
2924 }
2925}
2926
2927SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2928 fCanvas->restoreToCount(fSaveCount);
2929}
reede8f30622016-03-23 18:59:25 -07002930
Florin Malitaee424ac2016-12-01 12:47:59 -05002931///////////////////////////////////////////////////////////////////////////////
2932
2933SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2934 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2935
Florin Malita439ace92016-12-02 12:05:41 -05002936SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2937 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2938
Florin Malitaee424ac2016-12-01 12:47:59 -05002939SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2940 (void)this->INHERITED::getSaveLayerStrategy(rec);
2941 return kNoLayer_SaveLayerStrategy;
2942}
2943
2944///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002945
reed73603f32016-09-20 08:42:38 -07002946static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2947static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2948static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2949static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2950static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2951static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002952
2953///////////////////////////////////////////////////////////////////////////////////////////////////
2954
2955SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2956 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002957 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002958 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2959 SkIPoint origin = dev->getOrigin();
2960 SkMatrix ctm = this->getTotalMatrix();
2961 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2962
2963 SkIRect clip = fMCRec->fRasterClip.getBounds();
2964 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002965 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002966 clip.setEmpty();
2967 }
2968
2969 fAllocator->updateHandle(handle, ctm, clip);
2970 return handle;
2971 }
2972 return nullptr;
2973}
2974
2975static bool install(SkBitmap* bm, const SkImageInfo& info,
2976 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002977 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002978}
2979
2980SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2981 SkBitmap* bm) {
2982 SkRasterHandleAllocator::Rec rec;
2983 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2984 return nullptr;
2985 }
2986 return rec.fHandle;
2987}
2988
2989std::unique_ptr<SkCanvas>
2990SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2991 const SkImageInfo& info, const Rec* rec) {
2992 if (!alloc || !supported_for_raster_canvas(info)) {
2993 return nullptr;
2994 }
2995
2996 SkBitmap bm;
2997 Handle hndl;
2998
2999 if (rec) {
3000 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3001 } else {
3002 hndl = alloc->allocBitmap(info, &bm);
3003 }
3004 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3005}