blob: 809c2014bf658800af8d9fbb676e425a1030370e [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Florin Malitaab244f02017-05-03 19:16:58 +000023#include "SkLights.h"
Mike Reed5df49342016-11-12 08:06:55 -060024#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080025#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000026#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050027#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070028#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070029#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070030#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000031#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040036#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000037#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070038#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000039#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000040#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080041#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070042#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080045#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050046#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070047
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050049#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050050#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051
reede3b38ce2016-01-08 09:18:44 -080052#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
53
Mike Reed139e5e02017-03-08 11:29:33 -050054class SkNoPixelsDevice : public SkBaseDevice {
55public:
56 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
57 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
Mike Reed566e53c2017-03-10 10:49:45 -050058 {
Mike Reede393a622017-03-10 16:35:25 -050059 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
60 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050061 }
Mike Reed139e5e02017-03-08 11:29:33 -050062
63 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050064 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050065 this->privateResize(bounds.width(), bounds.height());
66 }
67
68protected:
69 // We don't track the clip at all (for performance), but we have to respond to some queries.
70 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
71 void onSave() override {}
72 void onRestore() override {}
73 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
74 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
75 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
76 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
77 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
78 bool onClipIsAA() const override { return false; }
79 void onAsRgnClip(SkRegion* rgn) const override {
80 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
81 }
82 ClipType onGetClipType() const override {
83 return kRect_ClipType;
84 }
85
86 void drawPaint(const SkPaint& paint) override {}
87 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
88 void drawRect(const SkRect&, const SkPaint&) override {}
89 void drawOval(const SkRect&, const SkPaint&) override {}
90 void drawRRect(const SkRRect&, const SkPaint&) override {}
91 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
Hal Canaryb9642382017-06-27 09:58:56 -040092 void drawBitmap(const SkBitmap&, SkScalar x, SkScalar y, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -050093 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
94 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
95 SkCanvas::SrcRectConstraint) override {}
96 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
97 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
98 const SkPaint&) override {}
99 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
Mike Reed2f6b5a42017-03-19 15:04:17 -0400100 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -0500101
102private:
103 typedef SkBaseDevice INHERITED;
104};
105
106///////////////////////////////////////////////////////////////////////////////////////////////////
107
reedc83a2972015-07-16 07:40:45 -0700108/*
109 * Return true if the drawing this rect would hit every pixels in the canvas.
110 *
111 * Returns false if
112 * - rect does not contain the canvas' bounds
113 * - paint is not fill
114 * - paint would blur or otherwise change the coverage of the rect
115 */
116bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
117 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700118 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
119 (int)kNone_ShaderOverrideOpacity,
120 "need_matching_enums0");
121 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
122 (int)kOpaque_ShaderOverrideOpacity,
123 "need_matching_enums1");
124 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
125 (int)kNotOpaque_ShaderOverrideOpacity,
126 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700127
128 const SkISize size = this->getBaseLayerSize();
129 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500130
131 // if we're clipped at all, we can't overwrite the entire surface
132 {
133 SkBaseDevice* base = this->getDevice();
134 SkBaseDevice* top = this->getTopDevice();
135 if (base != top) {
136 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
137 }
138 if (!base->clipIsWideOpen()) {
139 return false;
140 }
reedc83a2972015-07-16 07:40:45 -0700141 }
142
143 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700144 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700145 return false; // conservative
146 }
halcanaryc5769b22016-08-10 07:13:21 -0700147
148 SkRect devRect;
149 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
150 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700151 return false;
152 }
153 }
154
155 if (paint) {
156 SkPaint::Style paintStyle = paint->getStyle();
157 if (!(paintStyle == SkPaint::kFill_Style ||
158 paintStyle == SkPaint::kStrokeAndFill_Style)) {
159 return false;
160 }
161 if (paint->getMaskFilter() || paint->getLooper()
162 || paint->getPathEffect() || paint->getImageFilter()) {
163 return false; // conservative
164 }
165 }
166 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
167}
168
169///////////////////////////////////////////////////////////////////////////////////////////////////
170
reedd990e2f2014-12-22 11:58:30 -0800171static bool gIgnoreSaveLayerBounds;
172void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
173 gIgnoreSaveLayerBounds = ignore;
174}
175bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
176 return gIgnoreSaveLayerBounds;
177}
178
reed0acf1b42014-12-22 16:12:38 -0800179static bool gTreatSpriteAsBitmap;
180void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
181 gTreatSpriteAsBitmap = spriteAsBitmap;
182}
183bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
184 return gTreatSpriteAsBitmap;
185}
186
reed@google.comda17f752012-08-16 18:27:05 +0000187// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188//#define SK_TRACE_SAVERESTORE
189
190#ifdef SK_TRACE_SAVERESTORE
191 static int gLayerCounter;
192 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
193 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
194
195 static int gRecCounter;
196 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
197 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
198
199 static int gCanvasCounter;
200 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
201 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
202#else
203 #define inc_layer()
204 #define dec_layer()
205 #define inc_rec()
206 #define dec_rec()
207 #define inc_canvas()
208 #define dec_canvas()
209#endif
210
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000211typedef SkTLazy<SkPaint> SkLazyPaint;
212
reedc83a2972015-07-16 07:40:45 -0700213void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000214 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700215 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
216 ? SkSurface::kDiscard_ContentChangeMode
217 : SkSurface::kRetain_ContentChangeMode);
218 }
219}
220
221void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
222 ShaderOverrideOpacity overrideOpacity) {
223 if (fSurfaceBase) {
224 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
225 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
226 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
227 // and therefore we don't care which mode we're in.
228 //
229 if (fSurfaceBase->outstandingImageSnapshot()) {
230 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
231 mode = SkSurface::kDiscard_ContentChangeMode;
232 }
233 }
234 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000235 }
236}
237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000240/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 The clip/matrix/proc are fields that reflect the top of the save/restore
242 stack. Whenever the canvas changes, it marks a dirty flag, and then before
243 these are used (assuming we're not on a layer) we rebuild these cache
244 values: they reflect the top of the save stack, but translated and clipped
245 by the device's XY offset and bitmap-bounds.
246*/
247struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400248 DeviceCM* fNext;
249 sk_sp<SkBaseDevice> fDevice;
250 SkRasterClip fClip;
251 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
252 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400253 sk_sp<SkImage> fClipImage;
254 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255
Florin Malita53f77bd2017-04-28 13:48:37 -0400256 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000257 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700258 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400259 , fDevice(std::move(device))
260 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700261 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000262 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400263 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400264 {}
reed@google.com4b226022011-01-11 18:32:13 +0000265
mtkleinfeaadee2015-04-08 11:25:48 -0700266 void reset(const SkIRect& bounds) {
267 SkASSERT(!fPaint);
268 SkASSERT(!fNext);
269 SkASSERT(fDevice);
270 fClip.setRect(bounds);
271 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272};
273
274/* This is the record we keep for each save/restore level in the stack.
275 Since a level optionally copies the matrix and/or stack, we have pointers
276 for these fields. If the value is copied for this level, the copy is
277 stored in the ...Storage field, and the pointer points to that. If the
278 value is not copied for this level, we ignore ...Storage, and just point
279 at the corresponding value in the previous level in the stack.
280*/
281class SkCanvas::MCRec {
282public:
reed1f836ee2014-07-07 07:49:34 -0700283 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700284 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 /* If there are any layers in the stack, this points to the top-most
286 one that is at or below this level in the stack (so we know what
287 bitmap/device to draw into from this level. This value is NOT
288 reference counted, since the real owner is either our fLayer field,
289 or a previous one in a lower level.)
290 */
Mike Reeda1361362017-03-07 09:37:29 -0500291 DeviceCM* fTopLayer;
292 SkConservativeClip fRasterClip;
293 SkMatrix fMatrix;
294 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295
Mike Reeda1361362017-03-07 09:37:29 -0500296 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700297 fFilter = nullptr;
298 fLayer = nullptr;
299 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800300 fMatrix.reset();
301 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700302
reedd9544982014-09-09 18:46:22 -0700303 // don't bother initializing fNext
304 inc_rec();
305 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400306 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700307 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700308 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700309 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800310 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700311
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312 // don't bother initializing fNext
313 inc_rec();
314 }
315 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000316 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700317 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000318 dec_rec();
319 }
mtkleinfeaadee2015-04-08 11:25:48 -0700320
321 void reset(const SkIRect& bounds) {
322 SkASSERT(fLayer);
323 SkASSERT(fDeferredSaveCount == 0);
324
325 fMatrix.reset();
326 fRasterClip.setRect(bounds);
327 fLayer->reset(bounds);
328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329};
330
Mike Reeda1361362017-03-07 09:37:29 -0500331class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332public:
Mike Reeda1361362017-03-07 09:37:29 -0500333 SkDrawIter(SkCanvas* canvas)
334 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
335 {}
reed@google.com4b226022011-01-11 18:32:13 +0000336
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000338 const DeviceCM* rec = fCurrLayer;
339 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400340 fDevice = rec->fDevice.get();
341 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700343 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 return true;
345 }
346 return false;
347 }
reed@google.com4b226022011-01-11 18:32:13 +0000348
reed@google.com6f8f2922011-03-04 22:27:10 +0000349 int getX() const { return fDevice->getOrigin().x(); }
350 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000352
Mike Reed99330ba2017-02-22 11:01:08 -0500353 SkBaseDevice* fDevice;
354
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 const DeviceCM* fCurrLayer;
357 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358};
359
Florin Malita713b8ef2017-04-28 10:57:24 -0400360#define FOR_EACH_TOP_DEVICE( code ) \
361 do { \
362 DeviceCM* layer = fMCRec->fTopLayer; \
363 while (layer) { \
364 SkBaseDevice* device = layer->fDevice.get(); \
365 if (device) { \
366 code; \
367 } \
368 layer = layer->fNext; \
369 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500370 } while (0)
371
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372/////////////////////////////////////////////////////////////////////////////
373
reeddbc3cef2015-04-29 12:18:57 -0700374static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
375 return lazy->isValid() ? lazy->get() : lazy->set(orig);
376}
377
378/**
379 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700380 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700381 */
reedd053ce92016-03-22 10:17:23 -0700382static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700383 SkImageFilter* imgf = paint.getImageFilter();
384 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700385 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700386 }
387
reedd053ce92016-03-22 10:17:23 -0700388 SkColorFilter* imgCFPtr;
389 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700390 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700391 }
reedd053ce92016-03-22 10:17:23 -0700392 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700393
394 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700395 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700396 // there is no existing paint colorfilter, so we can just return the imagefilter's
397 return imgCF;
398 }
399
400 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
401 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700402 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700403}
404
senorblanco87e066e2015-10-28 11:23:36 -0700405/**
406 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
407 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
408 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
409 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
410 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
411 * conservative "effective" bounds based on the settings in the paint... with one exception. This
412 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
413 * deliberately ignored.
414 */
415static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
416 const SkRect& rawBounds,
417 SkRect* storage) {
418 SkPaint tmpUnfiltered(paint);
419 tmpUnfiltered.setImageFilter(nullptr);
420 if (tmpUnfiltered.canComputeFastBounds()) {
421 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
422 } else {
423 return rawBounds;
424 }
425}
426
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427class AutoDrawLooper {
428public:
senorblanco87e066e2015-10-28 11:23:36 -0700429 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
430 // paint. It's used to determine the size of the offscreen layer for filters.
431 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700432 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700433 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000434 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800435#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800437#else
438 fFilter = nullptr;
439#endif
reed4a8126e2014-09-22 07:29:03 -0700440 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000441 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700442 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000443 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444
reedd053ce92016-03-22 10:17:23 -0700445 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700446 if (simplifiedCF) {
447 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700448 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700449 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700450 fPaint = paint;
451 }
452
453 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700454 /**
455 * We implement ImageFilters for a given draw by creating a layer, then applying the
456 * imagefilter to the pixels of that layer (its backing surface/image), and then
457 * we call restore() to xfer that layer to the main canvas.
458 *
459 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
460 * 2. Generate the src pixels:
461 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
462 * return (fPaint). We then draw the primitive (using srcover) into a cleared
463 * buffer/surface.
464 * 3. Restore the layer created in #1
465 * The imagefilter is passed the buffer/surface from the layer (now filled with the
466 * src pixels of the primitive). It returns a new "filtered" buffer, which we
467 * draw onto the previous layer using the xfermode from the original paint.
468 */
reed@google.com8926b162012-03-23 15:36:36 +0000469 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500470 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700471 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700472 SkRect storage;
473 if (rawBounds) {
474 // Make rawBounds include all paint outsets except for those due to image filters.
475 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
476 }
reedbfd5f172016-01-07 11:28:08 -0800477 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700478 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700479 fTempLayerForImageFilter = true;
480 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000481 }
482
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000483 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500484 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000485 fIsSimple = false;
486 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700487 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000488 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700489 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000490 }
491 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000492
reed@android.com8a1c16f2008-12-17 15:59:43 +0000493 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700494 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000495 fCanvas->internalRestore();
496 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000497 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000499
reed@google.com4e2b3d32011-04-07 14:18:59 +0000500 const SkPaint& paint() const {
501 SkASSERT(fPaint);
502 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000504
reed@google.com129ec222012-05-15 13:24:09 +0000505 bool next(SkDrawFilter::Type drawType) {
506 if (fDone) {
507 return false;
508 } else if (fIsSimple) {
509 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000510 return !fPaint->nothingToDraw();
511 } else {
512 return this->doNext(drawType);
513 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500517 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700518 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000519 SkCanvas* fCanvas;
520 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000521 SkDrawFilter* fFilter;
522 const SkPaint* fPaint;
523 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700524 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000525 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000526 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000527 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400528 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000529
530 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000531};
532
reed@google.com129ec222012-05-15 13:24:09 +0000533bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700534 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000535 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700536 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000537
reeddbc3cef2015-04-29 12:18:57 -0700538 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
539 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000540
reed5c476fb2015-04-20 08:04:21 -0700541 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700542 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700543 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000544 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000545
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000546 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000547 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000548 return false;
549 }
550 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000551 if (!fFilter->filter(paint, drawType)) {
552 fDone = true;
553 return false;
554 }
halcanary96fcdcc2015-08-27 07:41:13 -0700555 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000556 // no looper means we only draw once
557 fDone = true;
558 }
559 }
560 fPaint = paint;
561
562 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000563 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000564 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000565 }
566
567 // call this after any possible paint modifiers
568 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700569 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000570 return false;
571 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000572 return true;
573}
574
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575////////// macros to place around the internal draw calls //////////////////
576
reed3aafe112016-08-18 12:45:34 -0700577#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
578 this->predrawNotify(); \
579 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
580 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800581 SkDrawIter iter(this);
582
583
reed@google.com8926b162012-03-23 15:36:36 +0000584#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000585 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700586 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000587 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000588 SkDrawIter iter(this);
589
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000590#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000591 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700592 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000593 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000594 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000595
reedc83a2972015-07-16 07:40:45 -0700596#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
597 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700598 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700599 while (looper.next(type)) { \
600 SkDrawIter iter(this);
601
reed@google.com4e2b3d32011-04-07 14:18:59 +0000602#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603
604////////////////////////////////////////////////////////////////////////////
605
msarettfbfa2582016-08-12 08:29:08 -0700606static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
607 if (bounds.isEmpty()) {
608 return SkRect::MakeEmpty();
609 }
610
611 // Expand bounds out by 1 in case we are anti-aliasing. We store the
612 // bounds as floats to enable a faster quick reject implementation.
613 SkRect dst;
614 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
615 return dst;
616}
617
mtkleinfeaadee2015-04-08 11:25:48 -0700618void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
619 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700620 fMCRec->reset(bounds);
621
622 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500623 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400624 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700625 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700626 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700627}
628
reedd9544982014-09-09 18:46:22 -0700629SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800630 if (device && device->forceConservativeRasterClip()) {
631 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
632 }
reed42b73eb2015-11-20 13:42:42 -0800633
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000634 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800635 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700636 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637
638 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500639 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500640 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700641 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642
reeda499f902015-05-01 09:34:31 -0700643 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
644 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400645 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700646
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648
halcanary96fcdcc2015-08-27 07:41:13 -0700649 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000650
reedf92c8662014-08-18 08:02:43 -0700651 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700652 // The root device and the canvas should always have the same pixel geometry
653 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800654 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700655 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500656
Mike Reedc42a1cd2017-02-14 14:25:14 -0500657 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700658 }
msarettfbfa2582016-08-12 08:29:08 -0700659
reedf92c8662014-08-18 08:02:43 -0700660 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661}
662
reed@google.comcde92112011-07-06 20:00:52 +0000663SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000664 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700665 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000666{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000667 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000668
halcanary96fcdcc2015-08-27 07:41:13 -0700669 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000670}
671
reed96a857e2015-01-25 10:33:58 -0800672SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000673 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800674 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000675{
676 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700677
Mike Reed566e53c2017-03-10 10:49:45 -0500678 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700679 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700680}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000681
reed78e27682014-11-19 08:04:34 -0800682SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700683 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700684 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700685{
686 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700687
Mike Reed566e53c2017-03-10 10:49:45 -0500688 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
689 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700690}
691
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000692SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000693 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700694 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000695{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700697
reedd9544982014-09-09 18:46:22 -0700698 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699}
700
robertphillipsfcf78292015-06-19 11:49:52 -0700701SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
702 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700703 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700704{
705 inc_canvas();
706
707 this->init(device, flags);
708}
709
reed4a8126e2014-09-22 07:29:03 -0700710SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700711 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700712 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700713{
714 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700715
Hal Canary704cd322016-11-07 14:13:52 -0500716 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
717 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700718}
reed29c857d2014-09-21 10:25:07 -0700719
Mike Reed356f7c22017-01-10 11:58:39 -0500720SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
721 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700722 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
723 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500724 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700725{
726 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700727
Mike Reed356f7c22017-01-10 11:58:39 -0500728 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500729 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000730}
731
Mike Reed356f7c22017-01-10 11:58:39 -0500732SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
733
Matt Sarett31f99ce2017-04-11 08:46:01 -0400734#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
735SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
736 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
737 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
738 , fAllocator(nullptr)
739{
740 inc_canvas();
741
742 SkBitmap tmp(bitmap);
743 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
744 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
745 this->init(device.get(), kDefault_InitFlags);
746}
747#endif
748
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749SkCanvas::~SkCanvas() {
750 // free up the contents of our deque
751 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000752
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753 this->internalRestore(); // restore the last, since we're going away
754
halcanary385fe4d2015-08-26 13:07:48 -0700755 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000756
reed@android.com8a1c16f2008-12-17 15:59:43 +0000757 dec_canvas();
758}
759
fmalita53d9f1c2016-01-25 06:23:54 -0800760#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761SkDrawFilter* SkCanvas::getDrawFilter() const {
762 return fMCRec->fFilter;
763}
764
765SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700766 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
768 return filter;
769}
fmalita77650002016-01-21 18:47:11 -0800770#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000772SkMetaData& SkCanvas::getMetaData() {
773 // metadata users are rare, so we lazily allocate it. If that changes we
774 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700775 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000776 fMetaData = new SkMetaData;
777 }
778 return *fMetaData;
779}
780
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781///////////////////////////////////////////////////////////////////////////////
782
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000783void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700784 this->onFlush();
785}
786
787void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000788 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000789 if (device) {
790 device->flush();
791 }
792}
793
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000794SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000795 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000796 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
797}
798
senorblancoafc7cce2016-02-02 18:44:15 -0800799SkIRect SkCanvas::getTopLayerBounds() const {
800 SkBaseDevice* d = this->getTopDevice();
801 if (!d) {
802 return SkIRect::MakeEmpty();
803 }
804 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
805}
806
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000807SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000809 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400811 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812}
813
Florin Malita0ed3b642017-01-13 16:56:38 +0000814SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400815 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000816}
817
Mike Reed353196f2017-07-21 11:01:18 -0400818bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000819 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400820 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000821}
822
Mike Reed353196f2017-07-21 11:01:18 -0400823bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
824 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400825}
826
827bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
828 SkPixmap pm;
829 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
830}
831
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000832bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400833 SkPixmap pm;
834 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700835 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000836 }
837 return false;
838}
839
Matt Sarett03dd6d52017-01-23 12:15:09 -0500840bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000841 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000842 SkBaseDevice* device = this->getDevice();
843 if (!device) {
844 return false;
845 }
846
Matt Sarett03dd6d52017-01-23 12:15:09 -0500847 // This check gives us an early out and prevents generation ID churn on the surface.
848 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
849 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
850 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
851 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000852 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000853
Matt Sarett03dd6d52017-01-23 12:15:09 -0500854 // Tell our owning surface to bump its generation ID.
855 const bool completeOverwrite =
856 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700857 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700858
Matt Sarett03dd6d52017-01-23 12:15:09 -0500859 // This can still fail, most notably in the case of a invalid color type or alpha type
860 // conversion. We could pull those checks into this function and avoid the unnecessary
861 // generation ID bump. But then we would be performing those checks twice, since they
862 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400863 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000864}
reed@google.com51df9e32010-12-23 19:29:18 +0000865
reed@android.com8a1c16f2008-12-17 15:59:43 +0000866//////////////////////////////////////////////////////////////////////////////
867
reed2ff1fce2014-12-11 07:07:37 -0800868void SkCanvas::checkForDeferredSave() {
869 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800870 this->doSave();
871 }
872}
873
reedf0090cb2014-11-26 08:55:51 -0800874int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800875#ifdef SK_DEBUG
876 int count = 0;
877 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
878 for (;;) {
879 const MCRec* rec = (const MCRec*)iter.next();
880 if (!rec) {
881 break;
882 }
883 count += 1 + rec->fDeferredSaveCount;
884 }
885 SkASSERT(count == fSaveCount);
886#endif
887 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800888}
889
890int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800891 fSaveCount += 1;
892 fMCRec->fDeferredSaveCount += 1;
893 return this->getSaveCount() - 1; // return our prev value
894}
895
896void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800897 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700898
899 SkASSERT(fMCRec->fDeferredSaveCount > 0);
900 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800901 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800902}
903
904void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800905 if (fMCRec->fDeferredSaveCount > 0) {
906 SkASSERT(fSaveCount > 1);
907 fSaveCount -= 1;
908 fMCRec->fDeferredSaveCount -= 1;
909 } else {
910 // check for underflow
911 if (fMCStack.count() > 1) {
912 this->willRestore();
913 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700914 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800915 this->internalRestore();
916 this->didRestore();
917 }
reedf0090cb2014-11-26 08:55:51 -0800918 }
919}
920
921void SkCanvas::restoreToCount(int count) {
922 // sanity check
923 if (count < 1) {
924 count = 1;
925 }
mtkleinf0f14112014-12-12 08:46:25 -0800926
reedf0090cb2014-11-26 08:55:51 -0800927 int n = this->getSaveCount() - count;
928 for (int i = 0; i < n; ++i) {
929 this->restore();
930 }
931}
932
reed2ff1fce2014-12-11 07:07:37 -0800933void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000934 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700935 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000936 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000937
Mike Reedc42a1cd2017-02-14 14:25:14 -0500938 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939}
940
reed4960eee2015-12-18 07:09:18 -0800941bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800942 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000943}
944
reed4960eee2015-12-18 07:09:18 -0800945bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700946 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500947 SkIRect clipBounds = this->getDeviceClipBounds();
948 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000949 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000950 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000951
reed96e657d2015-03-10 17:30:07 -0700952 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
953
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000954 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700955 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800956 if (bounds && !imageFilter->canComputeFastBounds()) {
957 bounds = nullptr;
958 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000959 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000960 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700961 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000963
reed96e657d2015-03-10 17:30:07 -0700964 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 r.roundOut(&ir);
966 // early exit if the layer's bounds are clipped out
967 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800968 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500969 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700970 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700971 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000972 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000973 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 }
975 } else { // no user bounds, so just use the clip
976 ir = clipBounds;
977 }
reed180aec42015-03-11 10:39:04 -0700978 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979
reed4960eee2015-12-18 07:09:18 -0800980 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700981 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700982 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700983 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000984 }
985
986 if (intersection) {
987 *intersection = ir;
988 }
989 return true;
990}
991
reed4960eee2015-12-18 07:09:18 -0800992
reed4960eee2015-12-18 07:09:18 -0800993int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
994 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000995}
996
reed70ee31b2015-12-10 13:44:45 -0800997int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800998 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
999}
1000
1001int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001002 SkTCopyOnFirstWrite<SaveLayerRec> rec(origRec);
reed4960eee2015-12-18 07:09:18 -08001003 if (gIgnoreSaveLayerBounds) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001004 rec.writable()->fBounds = nullptr;
reed4960eee2015-12-18 07:09:18 -08001005 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001006
1007 SaveLayerStrategy strategy = this->getSaveLayerStrategy(*rec);
reed4960eee2015-12-18 07:09:18 -08001008 fSaveCount += 1;
Florin Malita53f77bd2017-04-28 13:48:37 -04001009 this->internalSaveLayer(*rec, strategy);
reed4960eee2015-12-18 07:09:18 -08001010 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001011}
1012
reeda2217ef2016-07-20 06:04:34 -07001013void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001014 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001015 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001016 SkDraw draw;
1017 SkRasterClip rc;
1018 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1019 if (!dst->accessPixels(&draw.fDst)) {
1020 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001021 }
reeda2217ef2016-07-20 06:04:34 -07001022 draw.fMatrix = &SkMatrix::I();
1023 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001024
1025 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001026 if (filter) {
1027 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1028 }
reeda2217ef2016-07-20 06:04:34 -07001029
Mike Reedc42a1cd2017-02-14 14:25:14 -05001030 int x = src->getOrigin().x() - dstOrigin.x();
1031 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001032 auto special = src->snapSpecial();
1033 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001034 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -07001035 }
robertphillips7354a4b2015-12-16 05:08:27 -08001036}
reed70ee31b2015-12-10 13:44:45 -08001037
reed129ed1c2016-02-22 06:42:31 -08001038static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1039 const SkPaint* paint) {
1040 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1041 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001042 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001043 const bool hasImageFilter = paint && paint->getImageFilter();
1044
1045 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1046 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1047 // force to L32
1048 return SkImageInfo::MakeN32(w, h, alphaType);
1049 } else {
1050 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001051 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001052 }
1053}
1054
reed4960eee2015-12-18 07:09:18 -08001055void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1056 const SkRect* bounds = rec.fBounds;
1057 const SkPaint* paint = rec.fPaint;
1058 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1059
reed8c30a812016-04-20 16:36:51 -07001060 SkLazyPaint lazyP;
1061 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1062 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001063 SkMatrix remainder;
1064 SkSize scale;
1065 /*
1066 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1067 * but they do handle scaling. To accommodate this, we do the following:
1068 *
1069 * 1. Stash off the current CTM
1070 * 2. Decompose the CTM into SCALE and REMAINDER
1071 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1072 * contains the REMAINDER
1073 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1074 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1075 * of the original imagefilter, and draw that (via drawSprite)
1076 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1077 *
1078 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1079 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1080 */
reed96a04f32016-04-25 09:25:15 -07001081 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001082 stashedMatrix.decomposeScale(&scale, &remainder))
1083 {
1084 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1085 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1086 SkPaint* p = lazyP.set(*paint);
1087 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1088 SkFilterQuality::kLow_SkFilterQuality,
1089 sk_ref_sp(imageFilter)));
1090 imageFilter = p->getImageFilter();
1091 paint = p;
1092 }
reed8c30a812016-04-20 16:36:51 -07001093
junov@chromium.orga907ac32012-02-24 21:54:07 +00001094 // do this before we create the layer. We don't call the public save() since
1095 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001096 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001097
junov@chromium.orga907ac32012-02-24 21:54:07 +00001098 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001099 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001100 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101 }
1102
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001103 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1104 // the clipRectBounds() call above?
1105 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001106 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001107 }
1108
reed4960eee2015-12-18 07:09:18 -08001109 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001110 SkPixelGeometry geo = fProps.pixelGeometry();
1111 if (paint) {
reed76033be2015-03-14 10:54:31 -07001112 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001113 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001114 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001115 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001116 }
1117 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001118
robertphillips5139e502016-07-19 05:10:40 -07001119 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001120 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001121 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001122 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001123 }
reedb2db8982014-11-13 12:41:02 -08001124
robertphillips5139e502016-07-19 05:10:40 -07001125 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001126 paint);
1127
Hal Canary704cd322016-11-07 14:13:52 -05001128 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001129 {
reed70ee31b2015-12-10 13:44:45 -08001130 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001131 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001132 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001133 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001134 preserveLCDText,
1135 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001136 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1137 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001138 return;
reed61f501f2015-04-29 08:34:00 -07001139 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001140 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001141 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142
Mike Reedb43a3e02017-02-11 10:18:58 -05001143 // only have a "next" if this new layer doesn't affect the clip (rare)
1144 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145 fMCRec->fLayer = layer;
1146 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001147
Mike Reedc61abee2017-02-28 17:45:27 -05001148 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001149 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001150 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001151 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001152
Mike Reedc42a1cd2017-02-14 14:25:14 -05001153 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1154
1155 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1156 if (layer->fNext) {
1157 // need to punch a hole in the previous device, so we don't draw there, given that
1158 // the new top-layer will allow drawing to happen "below" it.
1159 SkRegion hole(ir);
1160 do {
1161 layer = layer->fNext;
1162 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1163 } while (layer->fNext);
1164 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001165}
1166
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001167int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001168 if (0xFF == alpha) {
1169 return this->saveLayer(bounds, nullptr);
1170 } else {
1171 SkPaint tmpPaint;
1172 tmpPaint.setAlpha(alpha);
1173 return this->saveLayer(bounds, &tmpPaint);
1174 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001175}
1176
reed@android.com8a1c16f2008-12-17 15:59:43 +00001177void SkCanvas::internalRestore() {
1178 SkASSERT(fMCStack.count() != 0);
1179
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001180 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181 DeviceCM* layer = fMCRec->fLayer; // may be null
1182 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001183 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184
1185 // now do the normal restore()
1186 fMCRec->~MCRec(); // balanced in save()
1187 fMCStack.pop_back();
1188 fMCRec = (MCRec*)fMCStack.back();
1189
Mike Reedc42a1cd2017-02-14 14:25:14 -05001190 if (fMCRec) {
1191 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1192 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001193
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1195 since if we're being recorded, we don't want to record this (the
1196 recorder will have already recorded the restore).
1197 */
bsalomon49f085d2014-09-05 13:34:00 -07001198 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001199 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001200 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001201 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001202 layer->fPaint.get(),
1203 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001204 // restore what we smashed in internalSaveLayer
1205 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001206 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001207 delete layer;
reedb679ca82015-04-07 04:40:48 -07001208 } else {
1209 // we're at the root
reeda499f902015-05-01 09:34:31 -07001210 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001211 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001212 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001213 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001214 }
msarettfbfa2582016-08-12 08:29:08 -07001215
1216 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001217 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001218 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1219 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220}
1221
reede8f30622016-03-23 18:59:25 -07001222sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001223 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001224 props = &fProps;
1225 }
1226 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001227}
1228
reede8f30622016-03-23 18:59:25 -07001229sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001230 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001231 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001232}
1233
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001234SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001235 return this->onImageInfo();
1236}
1237
1238SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001239 SkBaseDevice* dev = this->getDevice();
1240 if (dev) {
1241 return dev->imageInfo();
1242 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001243 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001244 }
1245}
1246
brianosman898235c2016-04-06 07:38:23 -07001247bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001248 return this->onGetProps(props);
1249}
1250
1251bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001252 SkBaseDevice* dev = this->getDevice();
1253 if (dev) {
1254 if (props) {
1255 *props = fProps;
1256 }
1257 return true;
1258 } else {
1259 return false;
1260 }
1261}
1262
reed6ceeebd2016-03-09 14:26:26 -08001263bool SkCanvas::peekPixels(SkPixmap* pmap) {
1264 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001265}
1266
reed884e97c2015-05-26 11:31:54 -07001267bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001268 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001269 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001270}
1271
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001272void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001273 SkPixmap pmap;
1274 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001275 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001276 }
1277 if (info) {
1278 *info = pmap.info();
1279 }
1280 if (rowBytes) {
1281 *rowBytes = pmap.rowBytes();
1282 }
1283 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001284 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001285 }
reed884e97c2015-05-26 11:31:54 -07001286 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001287}
1288
reed884e97c2015-05-26 11:31:54 -07001289bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001290 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001291 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001292}
1293
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295
Florin Malita53f77bd2017-04-28 13:48:37 -04001296void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1297 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001299 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 paint = &tmp;
1301 }
reed@google.com4b226022011-01-11 18:32:13 +00001302
reed@google.com8926b162012-03-23 15:36:36 +00001303 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001304
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001306 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001307 paint = &looper.paint();
1308 SkImageFilter* filter = paint->getImageFilter();
1309 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001310 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001311 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1312 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001313 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1314 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001315 }
reed@google.com76dd2772012-01-05 21:15:07 +00001316 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001317 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001318 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 }
reeda2217ef2016-07-20 06:04:34 -07001320
reed@google.com4e2b3d32011-04-07 14:18:59 +00001321 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322}
1323
reed32704672015-12-16 08:27:10 -08001324/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001325
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001326void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001327 if (dx || dy) {
1328 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001329 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001330
reedfe69b502016-09-12 06:31:48 -07001331 // Translate shouldn't affect the is-scale-translateness of the matrix.
1332 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001333
Mike Reedc42a1cd2017-02-14 14:25:14 -05001334 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001335
reedfe69b502016-09-12 06:31:48 -07001336 this->didTranslate(dx,dy);
1337 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338}
1339
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001340void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001341 SkMatrix m;
1342 m.setScale(sx, sy);
1343 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344}
1345
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001346void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001347 SkMatrix m;
1348 m.setRotate(degrees);
1349 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350}
1351
bungeman7438bfc2016-07-12 15:01:19 -07001352void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1353 SkMatrix m;
1354 m.setRotate(degrees, px, py);
1355 this->concat(m);
1356}
1357
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001358void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001359 SkMatrix m;
1360 m.setSkew(sx, sy);
1361 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001362}
1363
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001364void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001365 if (matrix.isIdentity()) {
1366 return;
1367 }
1368
reed2ff1fce2014-12-11 07:07:37 -08001369 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001370 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001371 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001372
Mike Reed7627fa52017-02-08 10:07:53 -05001373 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001374
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001375 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001376}
1377
reed8c30a812016-04-20 16:36:51 -07001378void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001379 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001380 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001381
Mike Reedc42a1cd2017-02-14 14:25:14 -05001382 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001383}
1384
1385void SkCanvas::setMatrix(const SkMatrix& matrix) {
1386 this->checkForDeferredSave();
1387 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001388 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389}
1390
reed@android.com8a1c16f2008-12-17 15:59:43 +00001391void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001392 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001393}
1394
1395//////////////////////////////////////////////////////////////////////////////
1396
Mike Reedc1f77742016-12-09 09:00:50 -05001397void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001398 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001399 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1400 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001401}
1402
Mike Reedc1f77742016-12-09 09:00:50 -05001403void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001404 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001405
Mike Reed7627fa52017-02-08 10:07:53 -05001406 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001407
reedc64eff52015-11-21 12:39:45 -08001408 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001409 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1410 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001411 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412}
1413
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001414void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1415 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001416 if (fClipRestrictionRect.isEmpty()) {
1417 // we notify the device, but we *dont* resolve deferred saves (since we're just
1418 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001419 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001420 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001421 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001422 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001423 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001424 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001425 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1426 }
1427}
1428
Mike Reedc1f77742016-12-09 09:00:50 -05001429void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001430 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001431 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001432 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001433 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1434 } else {
1435 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001436 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001438
Mike Reedc1f77742016-12-09 09:00:50 -05001439void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001440 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001441
Brian Salomona3b45d42016-10-03 11:36:16 -04001442 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001443
Mike Reed7627fa52017-02-08 10:07:53 -05001444 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001445
Brian Salomona3b45d42016-10-03 11:36:16 -04001446 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1447 isAA);
1448 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001449}
1450
Mike Reedc1f77742016-12-09 09:00:50 -05001451void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001452 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001453 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001454
1455 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1456 SkRect r;
1457 if (path.isRect(&r)) {
1458 this->onClipRect(r, op, edgeStyle);
1459 return;
1460 }
1461 SkRRect rrect;
1462 if (path.isOval(&r)) {
1463 rrect.setOval(r);
1464 this->onClipRRect(rrect, op, edgeStyle);
1465 return;
1466 }
1467 if (path.isRRect(&rrect)) {
1468 this->onClipRRect(rrect, op, edgeStyle);
1469 return;
1470 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001471 }
robertphillips39f05382015-11-24 09:30:12 -08001472
1473 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001474}
1475
Mike Reedc1f77742016-12-09 09:00:50 -05001476void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001477 AutoValidateClip avc(this);
1478
Brian Salomona3b45d42016-10-03 11:36:16 -04001479 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001480
Mike Reed7627fa52017-02-08 10:07:53 -05001481 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482
Brian Salomona3b45d42016-10-03 11:36:16 -04001483 const SkPath* rasterClipPath = &path;
1484 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001485 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1486 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001487 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488}
1489
Mike Reedc1f77742016-12-09 09:00:50 -05001490void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001491 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001492 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001493}
1494
Mike Reedc1f77742016-12-09 09:00:50 -05001495void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001496 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001497
reed@google.com5c3d1472011-02-22 19:12:23 +00001498 AutoValidateClip avc(this);
1499
reed73603f32016-09-20 08:42:38 -07001500 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001501 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001502}
1503
reed@google.com819c9212011-02-23 18:56:55 +00001504#ifdef SK_DEBUG
1505void SkCanvas::validateClip() const {
1506 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001507 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001508 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001509 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001510 return;
1511 }
reed@google.com819c9212011-02-23 18:56:55 +00001512}
1513#endif
1514
Mike Reeda1361362017-03-07 09:37:29 -05001515bool SkCanvas::androidFramework_isClipAA() const {
1516 bool containsAA = false;
1517
1518 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1519
1520 return containsAA;
1521}
1522
1523class RgnAccumulator {
1524 SkRegion* fRgn;
1525public:
1526 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1527 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1528 SkIPoint origin = device->getOrigin();
1529 if (origin.x() | origin.y()) {
1530 rgn->translate(origin.x(), origin.y());
1531 }
1532 fRgn->op(*rgn, SkRegion::kUnion_Op);
1533 }
1534};
1535
1536void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1537 RgnAccumulator accum(rgn);
1538 SkRegion tmp;
1539
1540 rgn->setEmpty();
1541 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001542}
1543
reed@google.com5c3d1472011-02-22 19:12:23 +00001544///////////////////////////////////////////////////////////////////////////////
1545
reed@google.com754de5f2014-02-24 19:38:20 +00001546bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001547 return fMCRec->fRasterClip.isEmpty();
1548
1549 // TODO: should we only use the conservative answer in a recording canvas?
1550#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001551 SkBaseDevice* dev = this->getTopDevice();
1552 // if no device we return true
1553 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001554#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001555}
1556
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001557bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001558 SkBaseDevice* dev = this->getTopDevice();
1559 // if no device we return false
1560 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001561}
1562
msarettfbfa2582016-08-12 08:29:08 -07001563static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1564#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1565 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1566 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1567 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1568 return 0xF != _mm_movemask_ps(mask);
1569#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1570 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1571 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1572 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1573 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1574#else
1575 SkRect devRectAsRect;
1576 SkRect devClipAsRect;
1577 devRect.store(&devRectAsRect.fLeft);
1578 devClip.store(&devClipAsRect.fLeft);
1579 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1580#endif
1581}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001582
msarettfbfa2582016-08-12 08:29:08 -07001583// It's important for this function to not be inlined. Otherwise the compiler will share code
1584// between the fast path and the slow path, resulting in two slow paths.
1585static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1586 const SkMatrix& matrix) {
1587 SkRect deviceRect;
1588 matrix.mapRect(&deviceRect, src);
1589 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1590}
1591
1592bool SkCanvas::quickReject(const SkRect& src) const {
1593#ifdef SK_DEBUG
1594 // Verify that fDeviceClipBounds are set properly.
1595 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001596 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001597 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001598 } else {
msarettfbfa2582016-08-12 08:29:08 -07001599 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001600 }
msarettfbfa2582016-08-12 08:29:08 -07001601
msarett9637ea92016-08-18 14:03:30 -07001602 // Verify that fIsScaleTranslate is set properly.
1603 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001604#endif
1605
msarett9637ea92016-08-18 14:03:30 -07001606 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001607 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1608 }
1609
1610 // We inline the implementation of mapScaleTranslate() for the fast path.
1611 float sx = fMCRec->fMatrix.getScaleX();
1612 float sy = fMCRec->fMatrix.getScaleY();
1613 float tx = fMCRec->fMatrix.getTranslateX();
1614 float ty = fMCRec->fMatrix.getTranslateY();
1615 Sk4f scale(sx, sy, sx, sy);
1616 Sk4f trans(tx, ty, tx, ty);
1617
1618 // Apply matrix.
1619 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1620
1621 // Make sure left < right, top < bottom.
1622 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1623 Sk4f min = Sk4f::Min(ltrb, rblt);
1624 Sk4f max = Sk4f::Max(ltrb, rblt);
1625 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1626 // ARM this sequence generates the fastest (a single instruction).
1627 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1628
1629 // Check if the device rect is NaN or outside the clip.
1630 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001631}
1632
reed@google.com3b3e8952012-08-16 20:53:31 +00001633bool SkCanvas::quickReject(const SkPath& path) const {
1634 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001635}
1636
Mike Reed42e8c532017-01-23 14:09:13 -05001637SkRect SkCanvas::onGetLocalClipBounds() const {
1638 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001639 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001640 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641 }
1642
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001643 SkMatrix inverse;
1644 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001645 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001646 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001647 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648
Mike Reed42e8c532017-01-23 14:09:13 -05001649 SkRect bounds;
1650 SkRect r;
1651 // adjust it outwards in case we are antialiasing
1652 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001653
Mike Reed42e8c532017-01-23 14:09:13 -05001654 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1655 ibounds.fRight + inset, ibounds.fBottom + inset);
1656 inverse.mapRect(&bounds, r);
1657 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658}
1659
Mike Reed42e8c532017-01-23 14:09:13 -05001660SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001661 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001662}
1663
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001665 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001666}
1667
Brian Osman11052242016-10-27 14:47:55 -04001668GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001669 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001670 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001671}
1672
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001673GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001674 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001675 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001676}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001677
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001678void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1679 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001680 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001681 if (outer.isEmpty()) {
1682 return;
1683 }
1684 if (inner.isEmpty()) {
1685 this->drawRRect(outer, paint);
1686 return;
1687 }
1688
1689 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001690 // be able to return ...
1691 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001692 //
1693 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001694 if (!outer.getBounds().contains(inner.getBounds())) {
1695 return;
1696 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001697
1698 this->onDrawDRRect(outer, inner, paint);
1699}
1700
reed41af9662015-01-05 07:49:08 -08001701// These need to stop being virtual -- clients need to override the onDraw... versions
1702
1703void SkCanvas::drawPaint(const SkPaint& paint) {
1704 this->onDrawPaint(paint);
1705}
1706
1707void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001708 // To avoid redundant logic in our culling code and various backends, we always sort rects
1709 // before passing them along.
1710 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001711}
1712
msarettdca352e2016-08-26 06:37:45 -07001713void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1714 if (region.isEmpty()) {
1715 return;
1716 }
1717
1718 if (region.isRect()) {
1719 return this->drawIRect(region.getBounds(), paint);
1720 }
1721
1722 this->onDrawRegion(region, paint);
1723}
1724
reed41af9662015-01-05 07:49:08 -08001725void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001726 // To avoid redundant logic in our culling code and various backends, we always sort rects
1727 // before passing them along.
1728 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001729}
1730
1731void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1732 this->onDrawRRect(rrect, paint);
1733}
1734
1735void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1736 this->onDrawPoints(mode, count, pts, paint);
1737}
1738
Mike Reede88a1cb2017-03-17 09:50:46 -04001739void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1740 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001741 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001742 this->onDrawVerticesObject(vertices.get(), mode, paint);
1743}
1744
1745void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1746 RETURN_ON_NULL(vertices);
1747 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001748}
1749
1750void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1751 this->onDrawPath(path, paint);
1752}
1753
reeda85d4d02015-05-06 12:56:48 -07001754void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001755 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001756 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001757}
1758
reede47829b2015-08-06 10:02:53 -07001759void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1760 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001761 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001762 if (dst.isEmpty() || src.isEmpty()) {
1763 return;
1764 }
1765 this->onDrawImageRect(image, &src, dst, paint, constraint);
1766}
reed41af9662015-01-05 07:49:08 -08001767
reed84984ef2015-07-17 07:09:43 -07001768void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1769 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001770 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001771 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001772}
1773
reede47829b2015-08-06 10:02:53 -07001774void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1775 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001776 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001777 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1778 constraint);
1779}
reede47829b2015-08-06 10:02:53 -07001780
reed4c21dc52015-06-25 12:32:03 -07001781void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1782 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001783 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001784 if (dst.isEmpty()) {
1785 return;
1786 }
msarett552bca92016-08-03 06:53:26 -07001787 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1788 this->onDrawImageNine(image, center, dst, paint);
1789 } else {
reede47829b2015-08-06 10:02:53 -07001790 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001791 }
reed4c21dc52015-06-25 12:32:03 -07001792}
1793
msarett16882062016-08-16 09:31:08 -07001794void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1795 const SkPaint* paint) {
1796 RETURN_ON_NULL(image);
1797 if (dst.isEmpty()) {
1798 return;
1799 }
msarett71df2d72016-09-30 12:41:42 -07001800
1801 SkIRect bounds;
1802 Lattice latticePlusBounds = lattice;
1803 if (!latticePlusBounds.fBounds) {
1804 bounds = SkIRect::MakeWH(image->width(), image->height());
1805 latticePlusBounds.fBounds = &bounds;
1806 }
1807
1808 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1809 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001810 } else {
1811 this->drawImageRect(image, dst, paint);
1812 }
1813}
1814
reed41af9662015-01-05 07:49:08 -08001815void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001816 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001817 return;
1818 }
reed41af9662015-01-05 07:49:08 -08001819 this->onDrawBitmap(bitmap, dx, dy, paint);
1820}
1821
reede47829b2015-08-06 10:02:53 -07001822void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001823 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001824 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001825 return;
1826 }
reede47829b2015-08-06 10:02:53 -07001827 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001828}
1829
reed84984ef2015-07-17 07:09:43 -07001830void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1831 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001832 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001833}
1834
reede47829b2015-08-06 10:02:53 -07001835void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1836 SrcRectConstraint constraint) {
1837 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1838 constraint);
1839}
reede47829b2015-08-06 10:02:53 -07001840
reed41af9662015-01-05 07:49:08 -08001841void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1842 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001843 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001844 return;
1845 }
msarett552bca92016-08-03 06:53:26 -07001846 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1847 this->onDrawBitmapNine(bitmap, center, dst, paint);
1848 } else {
reeda5517e22015-07-14 10:54:12 -07001849 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001850 }
reed41af9662015-01-05 07:49:08 -08001851}
1852
msarettc573a402016-08-02 08:05:56 -07001853void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1854 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001855 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001856 return;
1857 }
msarett71df2d72016-09-30 12:41:42 -07001858
1859 SkIRect bounds;
1860 Lattice latticePlusBounds = lattice;
1861 if (!latticePlusBounds.fBounds) {
1862 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1863 latticePlusBounds.fBounds = &bounds;
1864 }
1865
1866 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1867 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001868 } else {
msarett16882062016-08-16 09:31:08 -07001869 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001870 }
msarettc573a402016-08-02 08:05:56 -07001871}
1872
reed71c3c762015-06-24 10:29:17 -07001873void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001874 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001875 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001876 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001877 if (count <= 0) {
1878 return;
1879 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001880 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001881 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001882 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001883}
1884
reedf70b5312016-03-04 16:36:20 -08001885void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1886 if (key) {
1887 this->onDrawAnnotation(rect, key, value);
1888 }
1889}
1890
reede47829b2015-08-06 10:02:53 -07001891void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1892 const SkPaint* paint, SrcRectConstraint constraint) {
1893 if (src) {
1894 this->drawImageRect(image, *src, dst, paint, constraint);
1895 } else {
1896 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1897 dst, paint, constraint);
1898 }
1899}
1900void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1901 const SkPaint* paint, SrcRectConstraint constraint) {
1902 if (src) {
1903 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1904 } else {
1905 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1906 dst, paint, constraint);
1907 }
1908}
1909
Mike Reed4204da22017-05-17 08:53:36 -04001910void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
1911 this->onDrawShadowRec(path, rec);
1912}
1913
1914void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1915 SkPaint paint;
1916 const SkRect& pathBounds = path.getBounds();
1917
1918 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1919 while (iter.next()) {
1920 iter.fDevice->drawShadow(path, rec);
1921 }
1922 LOOPER_END
1923}
1924
reed@android.com8a1c16f2008-12-17 15:59:43 +00001925//////////////////////////////////////////////////////////////////////////////
1926// These are the virtual drawing methods
1927//////////////////////////////////////////////////////////////////////////////
1928
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001929void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001930 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001931 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1932 }
1933}
1934
reed41af9662015-01-05 07:49:08 -08001935void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001936 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001937 this->internalDrawPaint(paint);
1938}
1939
1940void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001941 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001942
1943 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001944 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001945 }
1946
reed@google.com4e2b3d32011-04-07 14:18:59 +00001947 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001948}
1949
reed41af9662015-01-05 07:49:08 -08001950void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1951 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001952 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001953 if ((long)count <= 0) {
1954 return;
1955 }
1956
Mike Reed822128b2017-02-28 16:41:03 -05001957 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001958 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001959 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001960 // special-case 2 points (common for drawing a single line)
1961 if (2 == count) {
1962 r.set(pts[0], pts[1]);
1963 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001964 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001965 }
Mike Reed822128b2017-02-28 16:41:03 -05001966 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001967 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1968 return;
1969 }
1970 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001971 }
reed@google.coma584aed2012-05-16 14:06:02 +00001972
halcanary96fcdcc2015-08-27 07:41:13 -07001973 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001974
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001975 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001976
reed@android.com8a1c16f2008-12-17 15:59:43 +00001977 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001978 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001979 }
reed@google.com4b226022011-01-11 18:32:13 +00001980
reed@google.com4e2b3d32011-04-07 14:18:59 +00001981 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001982}
1983
reed4a167172016-08-18 17:15:25 -07001984static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1985 return ((intptr_t)paint.getImageFilter() |
1986#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1987 (intptr_t)canvas->getDrawFilter() |
1988#endif
1989 (intptr_t)paint.getLooper() ) != 0;
1990}
1991
reed41af9662015-01-05 07:49:08 -08001992void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001993 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
Brian Osman6e3ce402017-05-17 15:10:18 -04001994 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001995 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001996 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001997 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001998 return;
1999 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002000 }
reed@google.com4b226022011-01-11 18:32:13 +00002001
reed4a167172016-08-18 17:15:25 -07002002 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002003 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004
reed4a167172016-08-18 17:15:25 -07002005 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002006 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002007 }
2008
2009 LOOPER_END
2010 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002011 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002012 SkDrawIter iter(this);
2013 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002014 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002015 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002016 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002017}
2018
msarett44df6512016-08-25 13:54:30 -07002019void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002020 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002021 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002022 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002023 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2024 return;
2025 }
msarett44df6512016-08-25 13:54:30 -07002026 }
2027
Mike Reed822128b2017-02-28 16:41:03 -05002028 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002029
2030 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002031 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002032 }
2033
2034 LOOPER_END
2035}
2036
reed41af9662015-01-05 07:49:08 -08002037void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002038 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
Brian Osman6e3ce402017-05-17 15:10:18 -04002039 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002040 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002041 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002042 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002043 return;
2044 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002045 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002046
Mike Reed822128b2017-02-28 16:41:03 -05002047 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002048
2049 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002050 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002051 }
2052
2053 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002054}
2055
bsalomonac3aa242016-08-19 11:25:19 -07002056void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2057 SkScalar sweepAngle, bool useCenter,
2058 const SkPaint& paint) {
2059 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
Brian Osman6e3ce402017-05-17 15:10:18 -04002060 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002061 if (paint.canComputeFastBounds()) {
2062 SkRect storage;
2063 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002064 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002065 return;
2066 }
bsalomonac3aa242016-08-19 11:25:19 -07002067 }
2068
Mike Reed822128b2017-02-28 16:41:03 -05002069 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002070
2071 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002072 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002073 }
2074
2075 LOOPER_END
2076}
2077
reed41af9662015-01-05 07:49:08 -08002078void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002079 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002080 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002081 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002082 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2083 return;
2084 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002085 }
2086
2087 if (rrect.isRect()) {
2088 // call the non-virtual version
2089 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002090 return;
2091 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002092 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002093 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2094 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002095 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002096
Mike Reed822128b2017-02-28 16:41:03 -05002097 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002098
2099 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002100 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002101 }
2102
2103 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002104}
2105
Mike Reed822128b2017-02-28 16:41:03 -05002106void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002107 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002108 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002109 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2110 return;
2111 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002112 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002113
Mike Reed822128b2017-02-28 16:41:03 -05002114 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002115
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002116 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002117 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002118 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002119
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002120 LOOPER_END
2121}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002122
reed41af9662015-01-05 07:49:08 -08002123void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002124 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002125 if (!path.isFinite()) {
2126 return;
2127 }
2128
Mike Reed822128b2017-02-28 16:41:03 -05002129 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002130 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002131 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002132 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2133 return;
2134 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002135 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002136
Mike Reed822128b2017-02-28 16:41:03 -05002137 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002138 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002139 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002140 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002141 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002142 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002143
Mike Reed822128b2017-02-28 16:41:03 -05002144 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145
2146 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002147 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002148 }
2149
reed@google.com4e2b3d32011-04-07 14:18:59 +00002150 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151}
2152
reed262a71b2015-12-05 13:07:27 -08002153bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002154 if (!paint.getImageFilter()) {
2155 return false;
2156 }
2157
2158 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002159 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002160 return false;
2161 }
2162
2163 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2164 // Once we can filter and the filter will return a result larger than itself, we should be
2165 // able to remove this constraint.
2166 // skbug.com/4526
2167 //
2168 SkPoint pt;
2169 ctm.mapXY(x, y, &pt);
2170 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2171 return ir.contains(fMCRec->fRasterClip.getBounds());
2172}
2173
reeda85d4d02015-05-06 12:56:48 -07002174void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002175 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002176 SkRect bounds = SkRect::MakeXYWH(x, y,
2177 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002178 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002179 SkRect tmp = bounds;
2180 if (paint) {
2181 paint->computeFastBounds(tmp, &tmp);
2182 }
2183 if (this->quickReject(tmp)) {
2184 return;
2185 }
reeda85d4d02015-05-06 12:56:48 -07002186 }
halcanary9d524f22016-03-29 09:03:52 -07002187
reeda85d4d02015-05-06 12:56:48 -07002188 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002189 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002190 paint = lazy.init();
2191 }
reed262a71b2015-12-05 13:07:27 -08002192
reeda2217ef2016-07-20 06:04:34 -07002193 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002194 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2195 *paint);
2196 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002197 special = this->getDevice()->makeSpecial(image);
2198 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002199 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002200 }
2201 }
2202
reed262a71b2015-12-05 13:07:27 -08002203 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2204
reeda85d4d02015-05-06 12:56:48 -07002205 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002206 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002207 if (special) {
2208 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002209 iter.fDevice->ctm().mapXY(x, y, &pt);
2210 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002211 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002212 SkScalarRoundToInt(pt.fY), pnt,
2213 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002214 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002215 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002216 }
reeda85d4d02015-05-06 12:56:48 -07002217 }
halcanary9d524f22016-03-29 09:03:52 -07002218
reeda85d4d02015-05-06 12:56:48 -07002219 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002220}
2221
reed41af9662015-01-05 07:49:08 -08002222void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002223 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002224 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002225 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002226 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002227 if (paint) {
2228 paint->computeFastBounds(dst, &storage);
2229 }
2230 if (this->quickReject(storage)) {
2231 return;
2232 }
reeda85d4d02015-05-06 12:56:48 -07002233 }
2234 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002235 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002236 paint = lazy.init();
2237 }
halcanary9d524f22016-03-29 09:03:52 -07002238
senorblancoc41e7e12015-12-07 12:51:30 -08002239 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002240 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002241
reeda85d4d02015-05-06 12:56:48 -07002242 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002243 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002244 }
halcanary9d524f22016-03-29 09:03:52 -07002245
reeda85d4d02015-05-06 12:56:48 -07002246 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002247}
2248
reed41af9662015-01-05 07:49:08 -08002249void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002250 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002251 SkDEBUGCODE(bitmap.validate();)
2252
reed33366972015-10-08 09:22:02 -07002253 if (bitmap.drawsNothing()) {
2254 return;
2255 }
2256
2257 SkLazyPaint lazy;
2258 if (nullptr == paint) {
2259 paint = lazy.init();
2260 }
2261
Mike Reed822128b2017-02-28 16:41:03 -05002262 SkRect bounds;
2263 bitmap.getBounds(&bounds);
2264 bounds.offset(x, y);
2265 bool canFastBounds = paint->canComputeFastBounds();
2266 if (canFastBounds) {
2267 SkRect storage;
2268 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002269 return;
2270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002271 }
reed@google.com4b226022011-01-11 18:32:13 +00002272
reeda2217ef2016-07-20 06:04:34 -07002273 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002274 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2275 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002276 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002277 special = this->getDevice()->makeSpecial(bitmap);
2278 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002279 drawAsSprite = false;
2280 }
2281 }
2282
Mike Reed822128b2017-02-28 16:41:03 -05002283 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002284
2285 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002286 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002287 if (special) {
reed262a71b2015-12-05 13:07:27 -08002288 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002289 iter.fDevice->ctm().mapXY(x, y, &pt);
2290 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002291 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002292 SkScalarRoundToInt(pt.fY), pnt,
2293 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002294 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002295 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002296 }
reed33366972015-10-08 09:22:02 -07002297 }
msarettfbfa2582016-08-12 08:29:08 -07002298
reed33366972015-10-08 09:22:02 -07002299 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002300}
2301
reed@google.com9987ec32011-09-07 11:57:52 +00002302// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002303void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002304 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002305 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002306 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 return;
2308 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002309
halcanary96fcdcc2015-08-27 07:41:13 -07002310 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002311 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002312 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2313 return;
2314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315 }
reed@google.com3d608122011-11-21 15:16:16 +00002316
reed@google.com33535f32012-09-25 15:37:50 +00002317 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002318 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002319 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002320 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002321
senorblancoc41e7e12015-12-07 12:51:30 -08002322 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002323 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002324
reed@google.com33535f32012-09-25 15:37:50 +00002325 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002326 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002327 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002328
reed@google.com33535f32012-09-25 15:37:50 +00002329 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002330}
2331
reed41af9662015-01-05 07:49:08 -08002332void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002333 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002334 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002335 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002336 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002337}
2338
reed4c21dc52015-06-25 12:32:03 -07002339void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2340 const SkPaint* paint) {
2341 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002342
halcanary96fcdcc2015-08-27 07:41:13 -07002343 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002344 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002345 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2346 return;
2347 }
reed@google.com3d608122011-11-21 15:16:16 +00002348 }
halcanary9d524f22016-03-29 09:03:52 -07002349
reed4c21dc52015-06-25 12:32:03 -07002350 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002351 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002352 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002353 }
halcanary9d524f22016-03-29 09:03:52 -07002354
senorblancoc41e7e12015-12-07 12:51:30 -08002355 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002356
reed4c21dc52015-06-25 12:32:03 -07002357 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002358 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002359 }
halcanary9d524f22016-03-29 09:03:52 -07002360
reed4c21dc52015-06-25 12:32:03 -07002361 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002362}
2363
reed41af9662015-01-05 07:49:08 -08002364void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2365 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002366 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002367 SkDEBUGCODE(bitmap.validate();)
2368
halcanary96fcdcc2015-08-27 07:41:13 -07002369 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002370 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002371 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2372 return;
2373 }
reed4c21dc52015-06-25 12:32:03 -07002374 }
halcanary9d524f22016-03-29 09:03:52 -07002375
reed4c21dc52015-06-25 12:32:03 -07002376 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002377 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002378 paint = lazy.init();
2379 }
halcanary9d524f22016-03-29 09:03:52 -07002380
senorblancoc41e7e12015-12-07 12:51:30 -08002381 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002382
reed4c21dc52015-06-25 12:32:03 -07002383 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002384 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002385 }
halcanary9d524f22016-03-29 09:03:52 -07002386
reed4c21dc52015-06-25 12:32:03 -07002387 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002388}
2389
msarett16882062016-08-16 09:31:08 -07002390void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2391 const SkPaint* paint) {
2392 if (nullptr == paint || paint->canComputeFastBounds()) {
2393 SkRect storage;
2394 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2395 return;
2396 }
2397 }
2398
2399 SkLazyPaint lazy;
2400 if (nullptr == paint) {
2401 paint = lazy.init();
2402 }
2403
2404 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2405
2406 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002407 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002408 }
2409
2410 LOOPER_END
2411}
2412
2413void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2414 const SkRect& dst, const SkPaint* paint) {
2415 if (nullptr == paint || paint->canComputeFastBounds()) {
2416 SkRect storage;
2417 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2418 return;
2419 }
2420 }
2421
2422 SkLazyPaint lazy;
2423 if (nullptr == paint) {
2424 paint = lazy.init();
2425 }
2426
2427 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2428
2429 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002430 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002431 }
2432
2433 LOOPER_END
2434}
2435
reed@google.comf67e4cf2011-03-15 20:56:58 +00002436class SkDeviceFilteredPaint {
2437public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002438 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002439 uint32_t filteredFlags = device->filterTextFlags(paint);
2440 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002441 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002442 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002443 fPaint = newPaint;
2444 } else {
2445 fPaint = &paint;
2446 }
2447 }
2448
reed@google.comf67e4cf2011-03-15 20:56:58 +00002449 const SkPaint& paint() const { return *fPaint; }
2450
2451private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002452 const SkPaint* fPaint;
2453 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002454};
2455
reed@google.come0d9ce82014-04-23 04:00:17 +00002456void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2457 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002458 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459
2460 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002461 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002462 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002463 }
2464
reed@google.com4e2b3d32011-04-07 14:18:59 +00002465 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466}
2467
reed@google.come0d9ce82014-04-23 04:00:17 +00002468void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2469 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002470 SkPoint textOffset = SkPoint::Make(0, 0);
2471
halcanary96fcdcc2015-08-27 07:41:13 -07002472 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002473
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002475 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002476 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002477 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002479
reed@google.com4e2b3d32011-04-07 14:18:59 +00002480 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481}
2482
reed@google.come0d9ce82014-04-23 04:00:17 +00002483void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2484 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002485
2486 SkPoint textOffset = SkPoint::Make(0, constY);
2487
halcanary96fcdcc2015-08-27 07:41:13 -07002488 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002489
reed@android.com8a1c16f2008-12-17 15:59:43 +00002490 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002491 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002492 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002493 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002494 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002495
reed@google.com4e2b3d32011-04-07 14:18:59 +00002496 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002497}
2498
reed@google.come0d9ce82014-04-23 04:00:17 +00002499void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2500 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002501 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002502
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002504 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002505 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002506 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002507
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002508 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002509}
2510
reed45561a02016-07-07 12:47:17 -07002511void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2512 const SkRect* cullRect, const SkPaint& paint) {
2513 if (cullRect && this->quickReject(*cullRect)) {
2514 return;
2515 }
2516
2517 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2518
2519 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002520 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002521 }
2522
2523 LOOPER_END
2524}
2525
fmalita00d5c2c2014-08-21 08:53:26 -07002526void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2527 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002528
fmalita85d5eb92015-03-04 11:20:12 -08002529 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002530 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002531 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002532 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002533 SkRect tmp;
2534 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2535 return;
2536 }
2537 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002538 }
2539
fmalita024f9962015-03-03 19:08:17 -08002540 // We cannot filter in the looper as we normally do, because the paint is
2541 // incomplete at this point (text-related attributes are embedded within blob run paints).
2542 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002543 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002544
fmalita85d5eb92015-03-04 11:20:12 -08002545 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002546
fmalitaaa1b9122014-08-28 14:32:24 -07002547 while (iter.next()) {
2548 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002549 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002550 }
2551
fmalitaaa1b9122014-08-28 14:32:24 -07002552 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002553
2554 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002555}
2556
Cary Clark2a475ea2017-04-28 15:35:12 -04002557void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2558 this->drawText(string.c_str(), string.size(), x, y, paint);
2559}
2560
reed@google.come0d9ce82014-04-23 04:00:17 +00002561// These will become non-virtual, so they always call the (virtual) onDraw... method
2562void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2563 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002564 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002565 if (byteLength) {
2566 this->onDrawText(text, byteLength, x, y, paint);
2567 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002568}
2569void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2570 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002571 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002572 if (byteLength) {
2573 this->onDrawPosText(text, byteLength, pos, paint);
2574 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002575}
2576void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2577 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002578 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002579 if (byteLength) {
2580 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2581 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002582}
2583void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2584 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002585 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002586 if (byteLength) {
2587 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2588 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002589}
reed45561a02016-07-07 12:47:17 -07002590void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2591 const SkRect* cullRect, const SkPaint& paint) {
2592 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2593 if (byteLength) {
2594 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2595 }
2596}
fmalita00d5c2c2014-08-21 08:53:26 -07002597void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2598 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002599 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002600 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002601 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002602}
reed@google.come0d9ce82014-04-23 04:00:17 +00002603
Mike Reede88a1cb2017-03-17 09:50:46 -04002604void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2605 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002606 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2607 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2608
2609 while (iter.next()) {
2610 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002611 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002612 }
2613
2614 LOOPER_END
2615}
2616
dandovb3c9d1c2014-08-12 08:34:29 -07002617void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002618 const SkPoint texCoords[4], SkBlendMode bmode,
2619 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002620 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002621 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002622 return;
2623 }
mtklein6cfa73a2014-08-13 13:33:49 -07002624
Mike Reedfaba3712016-11-03 14:45:31 -04002625 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002626}
2627
2628void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002629 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002630 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002631 // Since a patch is always within the convex hull of the control points, we discard it when its
2632 // bounding rectangle is completely outside the current clip.
2633 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002634 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002635 if (this->quickReject(bounds)) {
2636 return;
2637 }
mtklein6cfa73a2014-08-13 13:33:49 -07002638
Mike Reed435071e2017-05-23 11:22:56 -04002639 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2640
halcanary96fcdcc2015-08-27 07:41:13 -07002641 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002642
dandovecfff212014-08-04 10:02:00 -07002643 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002644 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002645 }
mtklein6cfa73a2014-08-13 13:33:49 -07002646
dandovecfff212014-08-04 10:02:00 -07002647 LOOPER_END
2648}
2649
reeda8db7282015-07-07 10:22:31 -07002650void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002651 RETURN_ON_NULL(dr);
2652 if (x || y) {
2653 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2654 this->onDrawDrawable(dr, &matrix);
2655 } else {
2656 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002657 }
2658}
2659
reeda8db7282015-07-07 10:22:31 -07002660void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002661 RETURN_ON_NULL(dr);
2662 if (matrix && matrix->isIdentity()) {
2663 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002664 }
reede3b38ce2016-01-08 09:18:44 -08002665 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002666}
2667
2668void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002669 // drawable bounds are no longer reliable (e.g. android displaylist)
2670 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002671 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002672}
2673
reed71c3c762015-06-24 10:29:17 -07002674void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002675 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002676 const SkRect* cull, const SkPaint* paint) {
2677 if (cull && this->quickReject(*cull)) {
2678 return;
2679 }
2680
2681 SkPaint pnt;
2682 if (paint) {
2683 pnt = *paint;
2684 }
halcanary9d524f22016-03-29 09:03:52 -07002685
halcanary96fcdcc2015-08-27 07:41:13 -07002686 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002687 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002688 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002689 }
2690 LOOPER_END
2691}
2692
reedf70b5312016-03-04 16:36:20 -08002693void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2694 SkASSERT(key);
2695
2696 SkPaint paint;
2697 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2698 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002699 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002700 }
2701 LOOPER_END
2702}
2703
reed@android.com8a1c16f2008-12-17 15:59:43 +00002704//////////////////////////////////////////////////////////////////////////////
2705// These methods are NOT virtual, and therefore must call back into virtual
2706// methods, rather than actually drawing themselves.
2707//////////////////////////////////////////////////////////////////////////////
2708
reed374772b2016-10-05 17:33:02 -07002709void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002710 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711 SkPaint paint;
2712
2713 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002714 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002715 this->drawPaint(paint);
2716}
2717
2718void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002719 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002720 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2722}
2723
Mike Reed3661bc92017-02-22 13:21:42 -05002724void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002725 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002727
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728 pts[0].set(x0, y0);
2729 pts[1].set(x1, y1);
2730 this->drawPoints(kLines_PointMode, 2, pts, paint);
2731}
2732
Mike Reed3661bc92017-02-22 13:21:42 -05002733void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002734 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 if (radius < 0) {
2736 radius = 0;
2737 }
2738
2739 SkRect r;
2740 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002741 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742}
2743
2744void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2745 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002746 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002747 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002748 SkRRect rrect;
2749 rrect.setRectXY(r, rx, ry);
2750 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 } else {
2752 this->drawRect(r, paint);
2753 }
2754}
2755
reed@android.com8a1c16f2008-12-17 15:59:43 +00002756void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2757 SkScalar sweepAngle, bool useCenter,
2758 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002759 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002760 if (oval.isEmpty() || !sweepAngle) {
2761 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762 }
bsalomon21af9ca2016-08-25 12:29:23 -07002763 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764}
2765
2766void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2767 const SkPath& path, SkScalar hOffset,
2768 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002769 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002771
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772 matrix.setTranslate(hOffset, vOffset);
2773 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2774}
2775
reed@android.comf76bacf2009-05-13 14:00:33 +00002776///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002777
2778/**
2779 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2780 * against the playback cost of recursing into the subpicture to get at its actual ops.
2781 *
2782 * For now we pick a conservatively small value, though measurement (and other heuristics like
2783 * the type of ops contained) may justify changing this value.
2784 */
2785#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002786
reedd5fa1a42014-08-09 11:08:05 -07002787void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002788 RETURN_ON_NULL(picture);
2789
reed1c2c4412015-04-30 13:09:24 -07002790 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002791 if (matrix && matrix->isIdentity()) {
2792 matrix = nullptr;
2793 }
2794 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2795 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2796 picture->playback(this);
2797 } else {
2798 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002799 }
2800}
robertphillips9b14f262014-06-04 05:40:44 -07002801
reedd5fa1a42014-08-09 11:08:05 -07002802void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2803 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002804 if (!paint || paint->canComputeFastBounds()) {
2805 SkRect bounds = picture->cullRect();
2806 if (paint) {
2807 paint->computeFastBounds(bounds, &bounds);
2808 }
2809 if (matrix) {
2810 matrix->mapRect(&bounds);
2811 }
2812 if (this->quickReject(bounds)) {
2813 return;
2814 }
2815 }
2816
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002817 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002818 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002819}
2820
reed@android.com8a1c16f2008-12-17 15:59:43 +00002821///////////////////////////////////////////////////////////////////////////////
2822///////////////////////////////////////////////////////////////////////////////
2823
reed3aafe112016-08-18 12:45:34 -07002824SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002825 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826
2827 SkASSERT(canvas);
2828
reed3aafe112016-08-18 12:45:34 -07002829 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830 fDone = !fImpl->next();
2831}
2832
2833SkCanvas::LayerIter::~LayerIter() {
2834 fImpl->~SkDrawIter();
2835}
2836
2837void SkCanvas::LayerIter::next() {
2838 fDone = !fImpl->next();
2839}
2840
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002841SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002842 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002843}
2844
2845const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002846 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847}
2848
2849const SkPaint& SkCanvas::LayerIter::paint() const {
2850 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002851 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002852 paint = &fDefaultPaint;
2853 }
2854 return *paint;
2855}
2856
Mike Reeda1361362017-03-07 09:37:29 -05002857void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2858 return fImpl->fDevice->onAsRgnClip(rgn);
2859}
2860
reed@android.com8a1c16f2008-12-17 15:59:43 +00002861int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2862int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002863
2864///////////////////////////////////////////////////////////////////////////////
2865
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002866static bool supported_for_raster_canvas(const SkImageInfo& info) {
2867 switch (info.alphaType()) {
2868 case kPremul_SkAlphaType:
2869 case kOpaque_SkAlphaType:
2870 break;
2871 default:
2872 return false;
2873 }
2874
2875 switch (info.colorType()) {
2876 case kAlpha_8_SkColorType:
2877 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002878 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002879 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002880 break;
2881 default:
2882 return false;
2883 }
2884
2885 return true;
2886}
2887
Mike Reed5df49342016-11-12 08:06:55 -06002888std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
2889 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002890 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002891 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002892 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002893
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002894 SkBitmap bitmap;
2895 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002896 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002897 }
Mike Reed5df49342016-11-12 08:06:55 -06002898 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002899}
reedd5fa1a42014-08-09 11:08:05 -07002900
2901///////////////////////////////////////////////////////////////////////////////
2902
2903SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002904 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002905 : fCanvas(canvas)
2906 , fSaveCount(canvas->getSaveCount())
2907{
bsalomon49f085d2014-09-05 13:34:00 -07002908 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002909 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002910 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002911 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002912 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002913 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002914 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002915 canvas->save();
2916 }
mtklein6cfa73a2014-08-13 13:33:49 -07002917
bsalomon49f085d2014-09-05 13:34:00 -07002918 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002919 canvas->concat(*matrix);
2920 }
2921}
2922
2923SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2924 fCanvas->restoreToCount(fSaveCount);
2925}
reede8f30622016-03-23 18:59:25 -07002926
Florin Malitaee424ac2016-12-01 12:47:59 -05002927///////////////////////////////////////////////////////////////////////////////
2928
2929SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2930 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2931
Florin Malita439ace92016-12-02 12:05:41 -05002932SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2933 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2934
Florin Malitaee424ac2016-12-01 12:47:59 -05002935SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2936 (void)this->INHERITED::getSaveLayerStrategy(rec);
2937 return kNoLayer_SaveLayerStrategy;
2938}
2939
2940///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002941
reed73603f32016-09-20 08:42:38 -07002942static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2943static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2944static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2945static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2946static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2947static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002948
2949///////////////////////////////////////////////////////////////////////////////////////////////////
2950
2951SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2952 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002953 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002954 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2955 SkIPoint origin = dev->getOrigin();
2956 SkMatrix ctm = this->getTotalMatrix();
2957 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2958
2959 SkIRect clip = fMCRec->fRasterClip.getBounds();
2960 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002961 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002962 clip.setEmpty();
2963 }
2964
2965 fAllocator->updateHandle(handle, ctm, clip);
2966 return handle;
2967 }
2968 return nullptr;
2969}
2970
2971static bool install(SkBitmap* bm, const SkImageInfo& info,
2972 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002973 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002974}
2975
2976SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2977 SkBitmap* bm) {
2978 SkRasterHandleAllocator::Rec rec;
2979 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2980 return nullptr;
2981 }
2982 return rec.fHandle;
2983}
2984
2985std::unique_ptr<SkCanvas>
2986SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2987 const SkImageInfo& info, const Rec* rec) {
2988 if (!alloc || !supported_for_raster_canvas(info)) {
2989 return nullptr;
2990 }
2991
2992 SkBitmap bm;
2993 Handle hndl;
2994
2995 if (rec) {
2996 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2997 } else {
2998 hndl = alloc->allocBitmap(info, &bm);
2999 }
3000 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3001}