blob: 0f079aac01dd3b3a622022d93eb72146a8c4fec0 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Ben Wagner4bd3b092017-08-01 13:22:23 -040026#include "SkMSAN.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050027#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070028#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070029#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070030#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000031#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040036#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000037#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070038#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000039#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000040#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080041#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070042#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080045#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050046#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070047
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050049#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050050#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051
reede3b38ce2016-01-08 09:18:44 -080052#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
53
Mike Reed139e5e02017-03-08 11:29:33 -050054class SkNoPixelsDevice : public SkBaseDevice {
55public:
56 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
57 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
Mike Reed566e53c2017-03-10 10:49:45 -050058 {
Mike Reede393a622017-03-10 16:35:25 -050059 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
60 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050061 }
Mike Reed139e5e02017-03-08 11:29:33 -050062
63 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050064 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050065 this->privateResize(bounds.width(), bounds.height());
66 }
67
68protected:
69 // We don't track the clip at all (for performance), but we have to respond to some queries.
70 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
71 void onSave() override {}
72 void onRestore() override {}
73 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
74 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
75 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
76 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
77 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
78 bool onClipIsAA() const override { return false; }
79 void onAsRgnClip(SkRegion* rgn) const override {
80 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
81 }
82 ClipType onGetClipType() const override {
83 return kRect_ClipType;
84 }
85
86 void drawPaint(const SkPaint& paint) override {}
87 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
88 void drawRect(const SkRect&, const SkPaint&) override {}
89 void drawOval(const SkRect&, const SkPaint&) override {}
90 void drawRRect(const SkRRect&, const SkPaint&) override {}
91 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
Hal Canaryb9642382017-06-27 09:58:56 -040092 void drawBitmap(const SkBitmap&, SkScalar x, SkScalar y, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -050093 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
94 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
95 SkCanvas::SrcRectConstraint) override {}
96 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
97 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
98 const SkPaint&) override {}
99 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
Mike Reed2f6b5a42017-03-19 15:04:17 -0400100 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -0500101
102private:
103 typedef SkBaseDevice INHERITED;
104};
105
106///////////////////////////////////////////////////////////////////////////////////////////////////
107
reedc83a2972015-07-16 07:40:45 -0700108/*
109 * Return true if the drawing this rect would hit every pixels in the canvas.
110 *
111 * Returns false if
112 * - rect does not contain the canvas' bounds
113 * - paint is not fill
114 * - paint would blur or otherwise change the coverage of the rect
115 */
116bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
117 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700118 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
119 (int)kNone_ShaderOverrideOpacity,
120 "need_matching_enums0");
121 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
122 (int)kOpaque_ShaderOverrideOpacity,
123 "need_matching_enums1");
124 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
125 (int)kNotOpaque_ShaderOverrideOpacity,
126 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700127
128 const SkISize size = this->getBaseLayerSize();
129 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500130
131 // if we're clipped at all, we can't overwrite the entire surface
132 {
133 SkBaseDevice* base = this->getDevice();
134 SkBaseDevice* top = this->getTopDevice();
135 if (base != top) {
136 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
137 }
138 if (!base->clipIsWideOpen()) {
139 return false;
140 }
reedc83a2972015-07-16 07:40:45 -0700141 }
142
143 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700144 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700145 return false; // conservative
146 }
halcanaryc5769b22016-08-10 07:13:21 -0700147
148 SkRect devRect;
149 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
150 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700151 return false;
152 }
153 }
154
155 if (paint) {
156 SkPaint::Style paintStyle = paint->getStyle();
157 if (!(paintStyle == SkPaint::kFill_Style ||
158 paintStyle == SkPaint::kStrokeAndFill_Style)) {
159 return false;
160 }
161 if (paint->getMaskFilter() || paint->getLooper()
162 || paint->getPathEffect() || paint->getImageFilter()) {
163 return false; // conservative
164 }
165 }
166 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
167}
168
169///////////////////////////////////////////////////////////////////////////////////////////////////
170
reedd990e2f2014-12-22 11:58:30 -0800171static bool gIgnoreSaveLayerBounds;
172void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
173 gIgnoreSaveLayerBounds = ignore;
174}
175bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
176 return gIgnoreSaveLayerBounds;
177}
178
reed0acf1b42014-12-22 16:12:38 -0800179static bool gTreatSpriteAsBitmap;
180void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
181 gTreatSpriteAsBitmap = spriteAsBitmap;
182}
183bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
184 return gTreatSpriteAsBitmap;
185}
186
reed@google.comda17f752012-08-16 18:27:05 +0000187// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188//#define SK_TRACE_SAVERESTORE
189
190#ifdef SK_TRACE_SAVERESTORE
191 static int gLayerCounter;
192 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
193 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
194
195 static int gRecCounter;
196 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
197 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
198
199 static int gCanvasCounter;
200 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
201 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
202#else
203 #define inc_layer()
204 #define dec_layer()
205 #define inc_rec()
206 #define dec_rec()
207 #define inc_canvas()
208 #define dec_canvas()
209#endif
210
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000211typedef SkTLazy<SkPaint> SkLazyPaint;
212
reedc83a2972015-07-16 07:40:45 -0700213void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000214 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700215 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
216 ? SkSurface::kDiscard_ContentChangeMode
217 : SkSurface::kRetain_ContentChangeMode);
218 }
219}
220
221void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
222 ShaderOverrideOpacity overrideOpacity) {
223 if (fSurfaceBase) {
224 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
225 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
226 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
227 // and therefore we don't care which mode we're in.
228 //
229 if (fSurfaceBase->outstandingImageSnapshot()) {
230 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
231 mode = SkSurface::kDiscard_ContentChangeMode;
232 }
233 }
234 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000235 }
236}
237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000240/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 The clip/matrix/proc are fields that reflect the top of the save/restore
242 stack. Whenever the canvas changes, it marks a dirty flag, and then before
243 these are used (assuming we're not on a layer) we rebuild these cache
244 values: they reflect the top of the save stack, but translated and clipped
245 by the device's XY offset and bitmap-bounds.
246*/
247struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400248 DeviceCM* fNext;
249 sk_sp<SkBaseDevice> fDevice;
250 SkRasterClip fClip;
251 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
252 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400253 sk_sp<SkImage> fClipImage;
254 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255
Florin Malita53f77bd2017-04-28 13:48:37 -0400256 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000257 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700258 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400259 , fDevice(std::move(device))
260 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700261 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000262 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400263 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400264 {}
reed@google.com4b226022011-01-11 18:32:13 +0000265
mtkleinfeaadee2015-04-08 11:25:48 -0700266 void reset(const SkIRect& bounds) {
267 SkASSERT(!fPaint);
268 SkASSERT(!fNext);
269 SkASSERT(fDevice);
270 fClip.setRect(bounds);
271 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272};
273
274/* This is the record we keep for each save/restore level in the stack.
275 Since a level optionally copies the matrix and/or stack, we have pointers
276 for these fields. If the value is copied for this level, the copy is
277 stored in the ...Storage field, and the pointer points to that. If the
278 value is not copied for this level, we ignore ...Storage, and just point
279 at the corresponding value in the previous level in the stack.
280*/
281class SkCanvas::MCRec {
282public:
reed1f836ee2014-07-07 07:49:34 -0700283 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700284 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 /* If there are any layers in the stack, this points to the top-most
286 one that is at or below this level in the stack (so we know what
287 bitmap/device to draw into from this level. This value is NOT
288 reference counted, since the real owner is either our fLayer field,
289 or a previous one in a lower level.)
290 */
Mike Reeda1361362017-03-07 09:37:29 -0500291 DeviceCM* fTopLayer;
292 SkConservativeClip fRasterClip;
293 SkMatrix fMatrix;
294 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295
Mike Reeda1361362017-03-07 09:37:29 -0500296 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700297 fFilter = nullptr;
298 fLayer = nullptr;
299 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800300 fMatrix.reset();
301 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700302
reedd9544982014-09-09 18:46:22 -0700303 // don't bother initializing fNext
304 inc_rec();
305 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400306 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700307 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700308 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700309 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800310 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700311
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312 // don't bother initializing fNext
313 inc_rec();
314 }
315 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000316 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700317 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000318 dec_rec();
319 }
mtkleinfeaadee2015-04-08 11:25:48 -0700320
321 void reset(const SkIRect& bounds) {
322 SkASSERT(fLayer);
323 SkASSERT(fDeferredSaveCount == 0);
324
325 fMatrix.reset();
326 fRasterClip.setRect(bounds);
327 fLayer->reset(bounds);
328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329};
330
Mike Reeda1361362017-03-07 09:37:29 -0500331class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332public:
Mike Reeda1361362017-03-07 09:37:29 -0500333 SkDrawIter(SkCanvas* canvas)
334 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
335 {}
reed@google.com4b226022011-01-11 18:32:13 +0000336
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000338 const DeviceCM* rec = fCurrLayer;
339 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400340 fDevice = rec->fDevice.get();
341 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700343 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 return true;
345 }
346 return false;
347 }
reed@google.com4b226022011-01-11 18:32:13 +0000348
reed@google.com6f8f2922011-03-04 22:27:10 +0000349 int getX() const { return fDevice->getOrigin().x(); }
350 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000352
Mike Reed99330ba2017-02-22 11:01:08 -0500353 SkBaseDevice* fDevice;
354
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 const DeviceCM* fCurrLayer;
357 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358};
359
Florin Malita713b8ef2017-04-28 10:57:24 -0400360#define FOR_EACH_TOP_DEVICE( code ) \
361 do { \
362 DeviceCM* layer = fMCRec->fTopLayer; \
363 while (layer) { \
364 SkBaseDevice* device = layer->fDevice.get(); \
365 if (device) { \
366 code; \
367 } \
368 layer = layer->fNext; \
369 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500370 } while (0)
371
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372/////////////////////////////////////////////////////////////////////////////
373
reeddbc3cef2015-04-29 12:18:57 -0700374static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
375 return lazy->isValid() ? lazy->get() : lazy->set(orig);
376}
377
378/**
379 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700380 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700381 */
reedd053ce92016-03-22 10:17:23 -0700382static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700383 SkImageFilter* imgf = paint.getImageFilter();
384 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700385 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700386 }
387
reedd053ce92016-03-22 10:17:23 -0700388 SkColorFilter* imgCFPtr;
389 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700390 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700391 }
reedd053ce92016-03-22 10:17:23 -0700392 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700393
394 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700395 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700396 // there is no existing paint colorfilter, so we can just return the imagefilter's
397 return imgCF;
398 }
399
400 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
401 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700402 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700403}
404
senorblanco87e066e2015-10-28 11:23:36 -0700405/**
406 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
407 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
408 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
409 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
410 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
411 * conservative "effective" bounds based on the settings in the paint... with one exception. This
412 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
413 * deliberately ignored.
414 */
415static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
416 const SkRect& rawBounds,
417 SkRect* storage) {
418 SkPaint tmpUnfiltered(paint);
419 tmpUnfiltered.setImageFilter(nullptr);
420 if (tmpUnfiltered.canComputeFastBounds()) {
421 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
422 } else {
423 return rawBounds;
424 }
425}
426
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427class AutoDrawLooper {
428public:
senorblanco87e066e2015-10-28 11:23:36 -0700429 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
430 // paint. It's used to determine the size of the offscreen layer for filters.
431 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700432 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700433 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000434 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800435#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800437#else
438 fFilter = nullptr;
439#endif
reed4a8126e2014-09-22 07:29:03 -0700440 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000441 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700442 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000443 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444
reedd053ce92016-03-22 10:17:23 -0700445 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700446 if (simplifiedCF) {
447 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700448 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700449 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700450 fPaint = paint;
451 }
452
453 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700454 /**
455 * We implement ImageFilters for a given draw by creating a layer, then applying the
456 * imagefilter to the pixels of that layer (its backing surface/image), and then
457 * we call restore() to xfer that layer to the main canvas.
458 *
459 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
460 * 2. Generate the src pixels:
461 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
462 * return (fPaint). We then draw the primitive (using srcover) into a cleared
463 * buffer/surface.
464 * 3. Restore the layer created in #1
465 * The imagefilter is passed the buffer/surface from the layer (now filled with the
466 * src pixels of the primitive). It returns a new "filtered" buffer, which we
467 * draw onto the previous layer using the xfermode from the original paint.
468 */
reed@google.com8926b162012-03-23 15:36:36 +0000469 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500470 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700471 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700472 SkRect storage;
473 if (rawBounds) {
474 // Make rawBounds include all paint outsets except for those due to image filters.
475 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
476 }
reedbfd5f172016-01-07 11:28:08 -0800477 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700478 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700479 fTempLayerForImageFilter = true;
480 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000481 }
482
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000483 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500484 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000485 fIsSimple = false;
486 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700487 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000488 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700489 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000490 }
491 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000492
reed@android.com8a1c16f2008-12-17 15:59:43 +0000493 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700494 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000495 fCanvas->internalRestore();
496 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000497 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000499
reed@google.com4e2b3d32011-04-07 14:18:59 +0000500 const SkPaint& paint() const {
501 SkASSERT(fPaint);
502 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000504
reed@google.com129ec222012-05-15 13:24:09 +0000505 bool next(SkDrawFilter::Type drawType) {
506 if (fDone) {
507 return false;
508 } else if (fIsSimple) {
509 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000510 return !fPaint->nothingToDraw();
511 } else {
512 return this->doNext(drawType);
513 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500517 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700518 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000519 SkCanvas* fCanvas;
520 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000521 SkDrawFilter* fFilter;
522 const SkPaint* fPaint;
523 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700524 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000525 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000526 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000527 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400528 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000529
530 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000531};
532
reed@google.com129ec222012-05-15 13:24:09 +0000533bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700534 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000535 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700536 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000537
reeddbc3cef2015-04-29 12:18:57 -0700538 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
539 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000540
reed5c476fb2015-04-20 08:04:21 -0700541 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700542 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700543 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000544 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000545
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000546 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000547 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000548 return false;
549 }
550 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000551 if (!fFilter->filter(paint, drawType)) {
552 fDone = true;
553 return false;
554 }
halcanary96fcdcc2015-08-27 07:41:13 -0700555 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000556 // no looper means we only draw once
557 fDone = true;
558 }
559 }
560 fPaint = paint;
561
562 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000563 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000564 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000565 }
566
567 // call this after any possible paint modifiers
568 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700569 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000570 return false;
571 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000572 return true;
573}
574
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575////////// macros to place around the internal draw calls //////////////////
576
reed3aafe112016-08-18 12:45:34 -0700577#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
578 this->predrawNotify(); \
579 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
580 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800581 SkDrawIter iter(this);
582
583
reed@google.com8926b162012-03-23 15:36:36 +0000584#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000585 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700586 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000587 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000588 SkDrawIter iter(this);
589
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000590#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000591 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700592 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000593 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000594 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000595
reedc83a2972015-07-16 07:40:45 -0700596#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
597 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700598 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700599 while (looper.next(type)) { \
600 SkDrawIter iter(this);
601
reed@google.com4e2b3d32011-04-07 14:18:59 +0000602#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603
604////////////////////////////////////////////////////////////////////////////
605
msarettfbfa2582016-08-12 08:29:08 -0700606static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
607 if (bounds.isEmpty()) {
608 return SkRect::MakeEmpty();
609 }
610
611 // Expand bounds out by 1 in case we are anti-aliasing. We store the
612 // bounds as floats to enable a faster quick reject implementation.
613 SkRect dst;
614 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
615 return dst;
616}
617
mtkleinfeaadee2015-04-08 11:25:48 -0700618void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
619 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700620 fMCRec->reset(bounds);
621
622 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500623 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400624 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700625 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700626 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700627}
628
reedd9544982014-09-09 18:46:22 -0700629SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800630 if (device && device->forceConservativeRasterClip()) {
631 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
632 }
reed42b73eb2015-11-20 13:42:42 -0800633
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000634 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800635 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700636 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637
638 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500639 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500640 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700641 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642
reeda499f902015-05-01 09:34:31 -0700643 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
644 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400645 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700646
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648
halcanary96fcdcc2015-08-27 07:41:13 -0700649 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000650
reedf92c8662014-08-18 08:02:43 -0700651 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700652 // The root device and the canvas should always have the same pixel geometry
653 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800654 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700655 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500656
Mike Reedc42a1cd2017-02-14 14:25:14 -0500657 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700658 }
msarettfbfa2582016-08-12 08:29:08 -0700659
reedf92c8662014-08-18 08:02:43 -0700660 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661}
662
reed@google.comcde92112011-07-06 20:00:52 +0000663SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000664 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700665 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000666{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000667 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000668
halcanary96fcdcc2015-08-27 07:41:13 -0700669 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000670}
671
reed96a857e2015-01-25 10:33:58 -0800672SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000673 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800674 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000675{
676 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700677
Mike Reed566e53c2017-03-10 10:49:45 -0500678 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700679 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700680}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000681
reed78e27682014-11-19 08:04:34 -0800682SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700683 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700684 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700685{
686 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700687
Mike Reed566e53c2017-03-10 10:49:45 -0500688 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
689 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700690}
691
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000692SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000693 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700694 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000695{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700697
reedd9544982014-09-09 18:46:22 -0700698 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699}
700
robertphillipsfcf78292015-06-19 11:49:52 -0700701SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
702 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700703 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700704{
705 inc_canvas();
706
707 this->init(device, flags);
708}
709
reed4a8126e2014-09-22 07:29:03 -0700710SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700711 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700712 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700713{
714 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700715
Hal Canary704cd322016-11-07 14:13:52 -0500716 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
717 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700718}
reed29c857d2014-09-21 10:25:07 -0700719
Mike Reed356f7c22017-01-10 11:58:39 -0500720SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
721 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700722 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
723 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500724 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700725{
726 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700727
Mike Reed356f7c22017-01-10 11:58:39 -0500728 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500729 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000730}
731
Mike Reed356f7c22017-01-10 11:58:39 -0500732SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
733
Matt Sarett31f99ce2017-04-11 08:46:01 -0400734#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
735SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
736 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
737 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
738 , fAllocator(nullptr)
739{
740 inc_canvas();
741
742 SkBitmap tmp(bitmap);
743 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
744 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
745 this->init(device.get(), kDefault_InitFlags);
746}
747#endif
748
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749SkCanvas::~SkCanvas() {
750 // free up the contents of our deque
751 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000752
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753 this->internalRestore(); // restore the last, since we're going away
754
halcanary385fe4d2015-08-26 13:07:48 -0700755 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000756
reed@android.com8a1c16f2008-12-17 15:59:43 +0000757 dec_canvas();
758}
759
fmalita53d9f1c2016-01-25 06:23:54 -0800760#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761SkDrawFilter* SkCanvas::getDrawFilter() const {
762 return fMCRec->fFilter;
763}
764
765SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700766 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
768 return filter;
769}
fmalita77650002016-01-21 18:47:11 -0800770#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000772SkMetaData& SkCanvas::getMetaData() {
773 // metadata users are rare, so we lazily allocate it. If that changes we
774 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700775 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000776 fMetaData = new SkMetaData;
777 }
778 return *fMetaData;
779}
780
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781///////////////////////////////////////////////////////////////////////////////
782
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000783void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700784 this->onFlush();
785}
786
787void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000788 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000789 if (device) {
790 device->flush();
791 }
792}
793
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000794SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000795 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000796 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
797}
798
senorblancoafc7cce2016-02-02 18:44:15 -0800799SkIRect SkCanvas::getTopLayerBounds() const {
800 SkBaseDevice* d = this->getTopDevice();
801 if (!d) {
802 return SkIRect::MakeEmpty();
803 }
804 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
805}
806
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000807SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000809 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400811 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812}
813
Florin Malita0ed3b642017-01-13 16:56:38 +0000814SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400815 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000816}
817
Mike Reed353196f2017-07-21 11:01:18 -0400818bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000819 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400820 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000821}
822
Mike Reed353196f2017-07-21 11:01:18 -0400823bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
824 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400825}
826
827bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
828 SkPixmap pm;
829 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
830}
831
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000832bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400833 SkPixmap pm;
834 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700835 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000836 }
837 return false;
838}
839
Matt Sarett03dd6d52017-01-23 12:15:09 -0500840bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000841 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000842 SkBaseDevice* device = this->getDevice();
843 if (!device) {
844 return false;
845 }
846
Matt Sarett03dd6d52017-01-23 12:15:09 -0500847 // This check gives us an early out and prevents generation ID churn on the surface.
848 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
849 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
850 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
851 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000852 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000853
Matt Sarett03dd6d52017-01-23 12:15:09 -0500854 // Tell our owning surface to bump its generation ID.
855 const bool completeOverwrite =
856 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700857 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700858
Matt Sarett03dd6d52017-01-23 12:15:09 -0500859 // This can still fail, most notably in the case of a invalid color type or alpha type
860 // conversion. We could pull those checks into this function and avoid the unnecessary
861 // generation ID bump. But then we would be performing those checks twice, since they
862 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400863 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000864}
reed@google.com51df9e32010-12-23 19:29:18 +0000865
reed@android.com8a1c16f2008-12-17 15:59:43 +0000866//////////////////////////////////////////////////////////////////////////////
867
reed2ff1fce2014-12-11 07:07:37 -0800868void SkCanvas::checkForDeferredSave() {
869 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800870 this->doSave();
871 }
872}
873
reedf0090cb2014-11-26 08:55:51 -0800874int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800875#ifdef SK_DEBUG
876 int count = 0;
877 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
878 for (;;) {
879 const MCRec* rec = (const MCRec*)iter.next();
880 if (!rec) {
881 break;
882 }
883 count += 1 + rec->fDeferredSaveCount;
884 }
885 SkASSERT(count == fSaveCount);
886#endif
887 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800888}
889
890int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800891 fSaveCount += 1;
892 fMCRec->fDeferredSaveCount += 1;
893 return this->getSaveCount() - 1; // return our prev value
894}
895
896void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800897 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700898
899 SkASSERT(fMCRec->fDeferredSaveCount > 0);
900 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800901 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800902}
903
904void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800905 if (fMCRec->fDeferredSaveCount > 0) {
906 SkASSERT(fSaveCount > 1);
907 fSaveCount -= 1;
908 fMCRec->fDeferredSaveCount -= 1;
909 } else {
910 // check for underflow
911 if (fMCStack.count() > 1) {
912 this->willRestore();
913 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700914 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800915 this->internalRestore();
916 this->didRestore();
917 }
reedf0090cb2014-11-26 08:55:51 -0800918 }
919}
920
921void SkCanvas::restoreToCount(int count) {
922 // sanity check
923 if (count < 1) {
924 count = 1;
925 }
mtkleinf0f14112014-12-12 08:46:25 -0800926
reedf0090cb2014-11-26 08:55:51 -0800927 int n = this->getSaveCount() - count;
928 for (int i = 0; i < n; ++i) {
929 this->restore();
930 }
931}
932
reed2ff1fce2014-12-11 07:07:37 -0800933void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000934 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700935 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000936 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000937
Mike Reedc42a1cd2017-02-14 14:25:14 -0500938 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939}
940
reed4960eee2015-12-18 07:09:18 -0800941bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800942 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000943}
944
reed4960eee2015-12-18 07:09:18 -0800945bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700946 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500947 SkIRect clipBounds = this->getDeviceClipBounds();
948 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000949 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000950 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000951
reed96e657d2015-03-10 17:30:07 -0700952 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
953
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000954 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700955 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
Mike Reed9cec1bc2018-01-19 12:57:01 -0500956 if (clipBounds.isEmpty()) {
957 return false;
958 }
senorblancodb64af32015-12-09 10:11:43 -0800959 if (bounds && !imageFilter->canComputeFastBounds()) {
960 bounds = nullptr;
961 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000962 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000963 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700964 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000966
reed96e657d2015-03-10 17:30:07 -0700967 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 r.roundOut(&ir);
969 // early exit if the layer's bounds are clipped out
970 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800971 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500972 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700973 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700974 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000975 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000976 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 }
978 } else { // no user bounds, so just use the clip
979 ir = clipBounds;
980 }
reed180aec42015-03-11 10:39:04 -0700981 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982
reed4960eee2015-12-18 07:09:18 -0800983 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700984 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700985 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700986 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000987 }
988
989 if (intersection) {
990 *intersection = ir;
991 }
992 return true;
993}
994
reed4960eee2015-12-18 07:09:18 -0800995
reed4960eee2015-12-18 07:09:18 -0800996int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
997 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000998}
999
reed70ee31b2015-12-10 13:44:45 -08001000int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001001 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1002}
1003
1004int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001005 SkTCopyOnFirstWrite<SaveLayerRec> rec(origRec);
reed4960eee2015-12-18 07:09:18 -08001006 if (gIgnoreSaveLayerBounds) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001007 rec.writable()->fBounds = nullptr;
reed4960eee2015-12-18 07:09:18 -08001008 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001009
1010 SaveLayerStrategy strategy = this->getSaveLayerStrategy(*rec);
reed4960eee2015-12-18 07:09:18 -08001011 fSaveCount += 1;
Florin Malita53f77bd2017-04-28 13:48:37 -04001012 this->internalSaveLayer(*rec, strategy);
reed4960eee2015-12-18 07:09:18 -08001013 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001014}
1015
reeda2217ef2016-07-20 06:04:34 -07001016void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001017 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001018 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001019 SkDraw draw;
1020 SkRasterClip rc;
1021 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1022 if (!dst->accessPixels(&draw.fDst)) {
1023 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001024 }
reeda2217ef2016-07-20 06:04:34 -07001025 draw.fMatrix = &SkMatrix::I();
1026 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001027
1028 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001029 if (filter) {
1030 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1031 }
reeda2217ef2016-07-20 06:04:34 -07001032
Mike Reedc42a1cd2017-02-14 14:25:14 -05001033 int x = src->getOrigin().x() - dstOrigin.x();
1034 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001035 auto special = src->snapSpecial();
1036 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001037 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -07001038 }
robertphillips7354a4b2015-12-16 05:08:27 -08001039}
reed70ee31b2015-12-10 13:44:45 -08001040
reed129ed1c2016-02-22 06:42:31 -08001041static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1042 const SkPaint* paint) {
1043 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1044 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001045 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001046 const bool hasImageFilter = paint && paint->getImageFilter();
1047
1048 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1049 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1050 // force to L32
1051 return SkImageInfo::MakeN32(w, h, alphaType);
1052 } else {
1053 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001054 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001055 }
1056}
1057
reed4960eee2015-12-18 07:09:18 -08001058void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1059 const SkRect* bounds = rec.fBounds;
1060 const SkPaint* paint = rec.fPaint;
1061 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1062
reed8c30a812016-04-20 16:36:51 -07001063 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001064 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001065 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001066 SkMatrix remainder;
1067 SkSize scale;
1068 /*
1069 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1070 * but they do handle scaling. To accommodate this, we do the following:
1071 *
1072 * 1. Stash off the current CTM
1073 * 2. Decompose the CTM into SCALE and REMAINDER
1074 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1075 * contains the REMAINDER
1076 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1077 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1078 * of the original imagefilter, and draw that (via drawSprite)
1079 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1080 *
1081 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1082 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1083 */
reed96a04f32016-04-25 09:25:15 -07001084 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001085 stashedMatrix.decomposeScale(&scale, &remainder))
1086 {
1087 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1088 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1089 SkPaint* p = lazyP.set(*paint);
1090 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1091 SkFilterQuality::kLow_SkFilterQuality,
1092 sk_ref_sp(imageFilter)));
1093 imageFilter = p->getImageFilter();
1094 paint = p;
1095 }
reed8c30a812016-04-20 16:36:51 -07001096
junov@chromium.orga907ac32012-02-24 21:54:07 +00001097 // do this before we create the layer. We don't call the public save() since
1098 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001099 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001100
junov@chromium.orga907ac32012-02-24 21:54:07 +00001101 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001102 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001103 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001104 }
1105
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001106 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1107 // the clipRectBounds() call above?
1108 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001109 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001110 }
1111
reed4960eee2015-12-18 07:09:18 -08001112 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001113 SkPixelGeometry geo = fProps.pixelGeometry();
1114 if (paint) {
reed76033be2015-03-14 10:54:31 -07001115 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001116 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001117 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001118 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001119 }
1120 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001121
robertphillips5139e502016-07-19 05:10:40 -07001122 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001123 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001124 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001125 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001126 }
reedb2db8982014-11-13 12:41:02 -08001127
robertphillips5139e502016-07-19 05:10:40 -07001128 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001129 paint);
1130
Hal Canary704cd322016-11-07 14:13:52 -05001131 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001132 {
reed70ee31b2015-12-10 13:44:45 -08001133 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001134 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001135 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001136 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001137 preserveLCDText,
1138 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001139 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1140 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001141 return;
reed61f501f2015-04-29 08:34:00 -07001142 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001143 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001144 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145
Mike Reedb43a3e02017-02-11 10:18:58 -05001146 // only have a "next" if this new layer doesn't affect the clip (rare)
1147 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001148 fMCRec->fLayer = layer;
1149 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001150
Mike Reedc61abee2017-02-28 17:45:27 -05001151 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001152 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001153 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001154 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001155
Mike Reedc42a1cd2017-02-14 14:25:14 -05001156 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1157
1158 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1159 if (layer->fNext) {
1160 // need to punch a hole in the previous device, so we don't draw there, given that
1161 // the new top-layer will allow drawing to happen "below" it.
1162 SkRegion hole(ir);
1163 do {
1164 layer = layer->fNext;
1165 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1166 } while (layer->fNext);
1167 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001168}
1169
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001170int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001171 if (0xFF == alpha) {
1172 return this->saveLayer(bounds, nullptr);
1173 } else {
1174 SkPaint tmpPaint;
1175 tmpPaint.setAlpha(alpha);
1176 return this->saveLayer(bounds, &tmpPaint);
1177 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001178}
1179
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180void SkCanvas::internalRestore() {
1181 SkASSERT(fMCStack.count() != 0);
1182
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001183 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184 DeviceCM* layer = fMCRec->fLayer; // may be null
1185 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001186 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001187
1188 // now do the normal restore()
1189 fMCRec->~MCRec(); // balanced in save()
1190 fMCStack.pop_back();
1191 fMCRec = (MCRec*)fMCStack.back();
1192
Mike Reedc42a1cd2017-02-14 14:25:14 -05001193 if (fMCRec) {
1194 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1195 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001196
reed@android.com8a1c16f2008-12-17 15:59:43 +00001197 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1198 since if we're being recorded, we don't want to record this (the
1199 recorder will have already recorded the restore).
1200 */
bsalomon49f085d2014-09-05 13:34:00 -07001201 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001202 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001203 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001204 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001205 layer->fPaint.get(),
1206 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001207 // restore what we smashed in internalSaveLayer
1208 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001209 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001210 delete layer;
reedb679ca82015-04-07 04:40:48 -07001211 } else {
1212 // we're at the root
reeda499f902015-05-01 09:34:31 -07001213 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001214 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001215 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001217 }
msarettfbfa2582016-08-12 08:29:08 -07001218
1219 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001220 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001221 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1222 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223}
1224
reede8f30622016-03-23 18:59:25 -07001225sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001226 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001227 props = &fProps;
1228 }
1229 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001230}
1231
reede8f30622016-03-23 18:59:25 -07001232sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001233 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001234 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001235}
1236
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001237SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001238 return this->onImageInfo();
1239}
1240
1241SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001242 SkBaseDevice* dev = this->getDevice();
1243 if (dev) {
1244 return dev->imageInfo();
1245 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001246 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001247 }
1248}
1249
brianosman898235c2016-04-06 07:38:23 -07001250bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001251 return this->onGetProps(props);
1252}
1253
1254bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001255 SkBaseDevice* dev = this->getDevice();
1256 if (dev) {
1257 if (props) {
1258 *props = fProps;
1259 }
1260 return true;
1261 } else {
1262 return false;
1263 }
1264}
1265
reed6ceeebd2016-03-09 14:26:26 -08001266bool SkCanvas::peekPixels(SkPixmap* pmap) {
1267 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001268}
1269
reed884e97c2015-05-26 11:31:54 -07001270bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001271 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001272 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001273}
1274
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001275void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001276 SkPixmap pmap;
1277 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001278 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001279 }
1280 if (info) {
1281 *info = pmap.info();
1282 }
1283 if (rowBytes) {
1284 *rowBytes = pmap.rowBytes();
1285 }
1286 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001287 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001288 }
reed884e97c2015-05-26 11:31:54 -07001289 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001290}
1291
reed884e97c2015-05-26 11:31:54 -07001292bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001293 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001294 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001295}
1296
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298
Florin Malita53f77bd2017-04-28 13:48:37 -04001299void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1300 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001302 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303 paint = &tmp;
1304 }
reed@google.com4b226022011-01-11 18:32:13 +00001305
reed@google.com8926b162012-03-23 15:36:36 +00001306 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001307
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001309 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001310 paint = &looper.paint();
1311 SkImageFilter* filter = paint->getImageFilter();
1312 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001313 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001314 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1315 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001316 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1317 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001318 }
reed@google.com76dd2772012-01-05 21:15:07 +00001319 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001320 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001321 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 }
reeda2217ef2016-07-20 06:04:34 -07001323
reed@google.com4e2b3d32011-04-07 14:18:59 +00001324 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325}
1326
reed32704672015-12-16 08:27:10 -08001327/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001328
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001329void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001330 if (dx || dy) {
1331 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001332 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001333
reedfe69b502016-09-12 06:31:48 -07001334 // Translate shouldn't affect the is-scale-translateness of the matrix.
1335 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001336
Mike Reedc42a1cd2017-02-14 14:25:14 -05001337 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001338
reedfe69b502016-09-12 06:31:48 -07001339 this->didTranslate(dx,dy);
1340 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341}
1342
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001343void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001344 SkMatrix m;
1345 m.setScale(sx, sy);
1346 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001347}
1348
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001349void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001350 SkMatrix m;
1351 m.setRotate(degrees);
1352 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001353}
1354
bungeman7438bfc2016-07-12 15:01:19 -07001355void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1356 SkMatrix m;
1357 m.setRotate(degrees, px, py);
1358 this->concat(m);
1359}
1360
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001361void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001362 SkMatrix m;
1363 m.setSkew(sx, sy);
1364 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001365}
1366
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001367void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001368 if (matrix.isIdentity()) {
1369 return;
1370 }
1371
reed2ff1fce2014-12-11 07:07:37 -08001372 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001373 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001374 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001375
Mike Reed7627fa52017-02-08 10:07:53 -05001376 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001377
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001378 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001379}
1380
reed8c30a812016-04-20 16:36:51 -07001381void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001382 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001383 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001384
Mike Reedc42a1cd2017-02-14 14:25:14 -05001385 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001386}
1387
1388void SkCanvas::setMatrix(const SkMatrix& matrix) {
1389 this->checkForDeferredSave();
1390 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001391 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001392}
1393
reed@android.com8a1c16f2008-12-17 15:59:43 +00001394void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001395 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001396}
1397
1398//////////////////////////////////////////////////////////////////////////////
1399
Mike Reedc1f77742016-12-09 09:00:50 -05001400void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001401 if (!rect.isFinite()) {
1402 return;
1403 }
reed2ff1fce2014-12-11 07:07:37 -08001404 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001405 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1406 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001407}
1408
Mike Reedc1f77742016-12-09 09:00:50 -05001409void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001410 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001411
Mike Reed7627fa52017-02-08 10:07:53 -05001412 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001413
reedc64eff52015-11-21 12:39:45 -08001414 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001415 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1416 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001417 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418}
1419
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001420void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1421 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001422 if (fClipRestrictionRect.isEmpty()) {
1423 // we notify the device, but we *dont* resolve deferred saves (since we're just
1424 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001425 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001426 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001427 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001428 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001429 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001430 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001431 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1432 }
1433}
1434
Mike Reedc1f77742016-12-09 09:00:50 -05001435void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001436 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001438 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001439 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1440 } else {
1441 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001442 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001443}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001444
Mike Reedc1f77742016-12-09 09:00:50 -05001445void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001446 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001447
Brian Salomona3b45d42016-10-03 11:36:16 -04001448 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001449
Mike Reed7627fa52017-02-08 10:07:53 -05001450 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001451
Mike Reed20800c82017-11-15 16:09:04 -05001452 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1453 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001454 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001455}
1456
Mike Reedc1f77742016-12-09 09:00:50 -05001457void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001458 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001459 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001460
1461 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1462 SkRect r;
1463 if (path.isRect(&r)) {
1464 this->onClipRect(r, op, edgeStyle);
1465 return;
1466 }
1467 SkRRect rrect;
1468 if (path.isOval(&r)) {
1469 rrect.setOval(r);
1470 this->onClipRRect(rrect, op, edgeStyle);
1471 return;
1472 }
1473 if (path.isRRect(&rrect)) {
1474 this->onClipRRect(rrect, op, edgeStyle);
1475 return;
1476 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001477 }
robertphillips39f05382015-11-24 09:30:12 -08001478
1479 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001480}
1481
Mike Reedc1f77742016-12-09 09:00:50 -05001482void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001483 AutoValidateClip avc(this);
1484
Brian Salomona3b45d42016-10-03 11:36:16 -04001485 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001486
Mike Reed7627fa52017-02-08 10:07:53 -05001487 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488
Brian Salomona3b45d42016-10-03 11:36:16 -04001489 const SkPath* rasterClipPath = &path;
1490 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001491 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1492 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001493 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001494}
1495
Mike Reedc1f77742016-12-09 09:00:50 -05001496void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001497 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001498 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001499}
1500
Mike Reedc1f77742016-12-09 09:00:50 -05001501void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001502 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001503
reed@google.com5c3d1472011-02-22 19:12:23 +00001504 AutoValidateClip avc(this);
1505
Mike Reed20800c82017-11-15 16:09:04 -05001506 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001507 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508}
1509
reed@google.com819c9212011-02-23 18:56:55 +00001510#ifdef SK_DEBUG
1511void SkCanvas::validateClip() const {
1512 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001513 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001514 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001515 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001516 return;
1517 }
reed@google.com819c9212011-02-23 18:56:55 +00001518}
1519#endif
1520
Mike Reeda1361362017-03-07 09:37:29 -05001521bool SkCanvas::androidFramework_isClipAA() const {
1522 bool containsAA = false;
1523
1524 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1525
1526 return containsAA;
1527}
1528
1529class RgnAccumulator {
1530 SkRegion* fRgn;
1531public:
1532 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1533 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1534 SkIPoint origin = device->getOrigin();
1535 if (origin.x() | origin.y()) {
1536 rgn->translate(origin.x(), origin.y());
1537 }
1538 fRgn->op(*rgn, SkRegion::kUnion_Op);
1539 }
1540};
1541
1542void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1543 RgnAccumulator accum(rgn);
1544 SkRegion tmp;
1545
1546 rgn->setEmpty();
1547 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001548}
1549
reed@google.com5c3d1472011-02-22 19:12:23 +00001550///////////////////////////////////////////////////////////////////////////////
1551
reed@google.com754de5f2014-02-24 19:38:20 +00001552bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001553 return fMCRec->fRasterClip.isEmpty();
1554
1555 // TODO: should we only use the conservative answer in a recording canvas?
1556#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001557 SkBaseDevice* dev = this->getTopDevice();
1558 // if no device we return true
1559 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001560#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001561}
1562
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001563bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001564 SkBaseDevice* dev = this->getTopDevice();
1565 // if no device we return false
1566 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001567}
1568
msarettfbfa2582016-08-12 08:29:08 -07001569static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1570#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1571 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1572 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1573 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1574 return 0xF != _mm_movemask_ps(mask);
1575#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1576 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1577 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1578 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1579 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1580#else
1581 SkRect devRectAsRect;
1582 SkRect devClipAsRect;
1583 devRect.store(&devRectAsRect.fLeft);
1584 devClip.store(&devClipAsRect.fLeft);
1585 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1586#endif
1587}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001588
msarettfbfa2582016-08-12 08:29:08 -07001589// It's important for this function to not be inlined. Otherwise the compiler will share code
1590// between the fast path and the slow path, resulting in two slow paths.
1591static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1592 const SkMatrix& matrix) {
1593 SkRect deviceRect;
1594 matrix.mapRect(&deviceRect, src);
1595 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1596}
1597
1598bool SkCanvas::quickReject(const SkRect& src) const {
1599#ifdef SK_DEBUG
1600 // Verify that fDeviceClipBounds are set properly.
1601 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001602 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001603 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001604 } else {
msarettfbfa2582016-08-12 08:29:08 -07001605 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001606 }
msarettfbfa2582016-08-12 08:29:08 -07001607
msarett9637ea92016-08-18 14:03:30 -07001608 // Verify that fIsScaleTranslate is set properly.
1609 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001610#endif
1611
msarett9637ea92016-08-18 14:03:30 -07001612 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001613 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1614 }
1615
1616 // We inline the implementation of mapScaleTranslate() for the fast path.
1617 float sx = fMCRec->fMatrix.getScaleX();
1618 float sy = fMCRec->fMatrix.getScaleY();
1619 float tx = fMCRec->fMatrix.getTranslateX();
1620 float ty = fMCRec->fMatrix.getTranslateY();
1621 Sk4f scale(sx, sy, sx, sy);
1622 Sk4f trans(tx, ty, tx, ty);
1623
1624 // Apply matrix.
1625 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1626
1627 // Make sure left < right, top < bottom.
1628 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1629 Sk4f min = Sk4f::Min(ltrb, rblt);
1630 Sk4f max = Sk4f::Max(ltrb, rblt);
1631 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1632 // ARM this sequence generates the fastest (a single instruction).
1633 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1634
1635 // Check if the device rect is NaN or outside the clip.
1636 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001637}
1638
reed@google.com3b3e8952012-08-16 20:53:31 +00001639bool SkCanvas::quickReject(const SkPath& path) const {
1640 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641}
1642
Mike Klein83c8dd92017-11-28 17:08:45 -05001643SkRect SkCanvas::getLocalClipBounds() const {
1644 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001645 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001646 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001647 }
1648
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001649 SkMatrix inverse;
1650 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001651 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001652 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001653 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001654
Mike Reed42e8c532017-01-23 14:09:13 -05001655 SkRect bounds;
1656 SkRect r;
1657 // adjust it outwards in case we are antialiasing
1658 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001659
Mike Reed42e8c532017-01-23 14:09:13 -05001660 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1661 ibounds.fRight + inset, ibounds.fBottom + inset);
1662 inverse.mapRect(&bounds, r);
1663 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664}
1665
Mike Klein83c8dd92017-11-28 17:08:45 -05001666SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001667 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001668}
1669
reed@android.com8a1c16f2008-12-17 15:59:43 +00001670const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001671 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001672}
1673
Brian Osman11052242016-10-27 14:47:55 -04001674GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001675 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001676 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001677}
1678
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001679GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001680 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001681 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001682}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001683
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001684void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1685 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001686 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001687 if (outer.isEmpty()) {
1688 return;
1689 }
1690 if (inner.isEmpty()) {
1691 this->drawRRect(outer, paint);
1692 return;
1693 }
1694
1695 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001696 // be able to return ...
1697 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001698 //
1699 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001700 if (!outer.getBounds().contains(inner.getBounds())) {
1701 return;
1702 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001703
1704 this->onDrawDRRect(outer, inner, paint);
1705}
1706
reed41af9662015-01-05 07:49:08 -08001707void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001708 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001709 this->onDrawPaint(paint);
1710}
1711
1712void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001713 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001714 // To avoid redundant logic in our culling code and various backends, we always sort rects
1715 // before passing them along.
1716 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001717}
1718
msarettdca352e2016-08-26 06:37:45 -07001719void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001720 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001721 if (region.isEmpty()) {
1722 return;
1723 }
1724
1725 if (region.isRect()) {
1726 return this->drawIRect(region.getBounds(), paint);
1727 }
1728
1729 this->onDrawRegion(region, paint);
1730}
1731
reed41af9662015-01-05 07:49:08 -08001732void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001733 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001734 // To avoid redundant logic in our culling code and various backends, we always sort rects
1735 // before passing them along.
1736 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001737}
1738
1739void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001740 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001741 this->onDrawRRect(rrect, paint);
1742}
1743
1744void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001745 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001746 this->onDrawPoints(mode, count, pts, paint);
1747}
1748
Mike Reede88a1cb2017-03-17 09:50:46 -04001749void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1750 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001751 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001752 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001753 this->onDrawVerticesObject(vertices.get(), mode, paint);
1754}
1755
1756void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001757 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001758 RETURN_ON_NULL(vertices);
1759 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001760}
1761
1762void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001763 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001764 this->onDrawPath(path, paint);
1765}
1766
reeda85d4d02015-05-06 12:56:48 -07001767void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001768 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001769 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001770 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001771}
1772
reede47829b2015-08-06 10:02:53 -07001773void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1774 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001775 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001776 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001777 if (dst.isEmpty() || src.isEmpty()) {
1778 return;
1779 }
1780 this->onDrawImageRect(image, &src, dst, paint, constraint);
1781}
reed41af9662015-01-05 07:49:08 -08001782
reed84984ef2015-07-17 07:09:43 -07001783void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1784 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001785 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001786 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001787}
1788
reede47829b2015-08-06 10:02:53 -07001789void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1790 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001791 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001792 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1793 constraint);
1794}
reede47829b2015-08-06 10:02:53 -07001795
reed4c21dc52015-06-25 12:32:03 -07001796void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1797 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001798 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001799 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001800 if (dst.isEmpty()) {
1801 return;
1802 }
msarett552bca92016-08-03 06:53:26 -07001803 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1804 this->onDrawImageNine(image, center, dst, paint);
1805 } else {
reede47829b2015-08-06 10:02:53 -07001806 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001807 }
reed4c21dc52015-06-25 12:32:03 -07001808}
1809
msarett16882062016-08-16 09:31:08 -07001810void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1811 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001812 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001813 RETURN_ON_NULL(image);
1814 if (dst.isEmpty()) {
1815 return;
1816 }
msarett71df2d72016-09-30 12:41:42 -07001817
1818 SkIRect bounds;
1819 Lattice latticePlusBounds = lattice;
1820 if (!latticePlusBounds.fBounds) {
1821 bounds = SkIRect::MakeWH(image->width(), image->height());
1822 latticePlusBounds.fBounds = &bounds;
1823 }
1824
1825 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1826 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001827 } else {
1828 this->drawImageRect(image, dst, paint);
1829 }
1830}
1831
reed41af9662015-01-05 07:49:08 -08001832void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001833 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001834 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001835 return;
1836 }
reed41af9662015-01-05 07:49:08 -08001837 this->onDrawBitmap(bitmap, dx, dy, paint);
1838}
1839
reede47829b2015-08-06 10:02:53 -07001840void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001841 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001842 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001843 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001844 return;
1845 }
reede47829b2015-08-06 10:02:53 -07001846 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001847}
1848
reed84984ef2015-07-17 07:09:43 -07001849void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1850 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001851 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001852}
1853
reede47829b2015-08-06 10:02:53 -07001854void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1855 SrcRectConstraint constraint) {
1856 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1857 constraint);
1858}
reede47829b2015-08-06 10:02:53 -07001859
reed41af9662015-01-05 07:49:08 -08001860void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1861 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001862 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001863 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001864 return;
1865 }
msarett552bca92016-08-03 06:53:26 -07001866 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1867 this->onDrawBitmapNine(bitmap, center, dst, paint);
1868 } else {
reeda5517e22015-07-14 10:54:12 -07001869 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001870 }
reed41af9662015-01-05 07:49:08 -08001871}
1872
msarettc573a402016-08-02 08:05:56 -07001873void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1874 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001875 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001876 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001877 return;
1878 }
msarett71df2d72016-09-30 12:41:42 -07001879
1880 SkIRect bounds;
1881 Lattice latticePlusBounds = lattice;
1882 if (!latticePlusBounds.fBounds) {
1883 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1884 latticePlusBounds.fBounds = &bounds;
1885 }
1886
1887 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1888 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001889 } else {
msarett16882062016-08-16 09:31:08 -07001890 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001891 }
msarettc573a402016-08-02 08:05:56 -07001892}
1893
reed71c3c762015-06-24 10:29:17 -07001894void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001895 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001896 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001897 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001898 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001899 if (count <= 0) {
1900 return;
1901 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001902 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001903 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001904 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001905}
1906
reedf70b5312016-03-04 16:36:20 -08001907void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001908 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001909 if (key) {
1910 this->onDrawAnnotation(rect, key, value);
1911 }
1912}
1913
reede47829b2015-08-06 10:02:53 -07001914void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1915 const SkPaint* paint, SrcRectConstraint constraint) {
1916 if (src) {
1917 this->drawImageRect(image, *src, dst, paint, constraint);
1918 } else {
1919 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1920 dst, paint, constraint);
1921 }
1922}
1923void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1924 const SkPaint* paint, SrcRectConstraint constraint) {
1925 if (src) {
1926 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1927 } else {
1928 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1929 dst, paint, constraint);
1930 }
1931}
1932
Mike Reed4204da22017-05-17 08:53:36 -04001933void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001934 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001935 this->onDrawShadowRec(path, rec);
1936}
1937
1938void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1939 SkPaint paint;
1940 const SkRect& pathBounds = path.getBounds();
1941
1942 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1943 while (iter.next()) {
1944 iter.fDevice->drawShadow(path, rec);
1945 }
1946 LOOPER_END
1947}
1948
reed@android.com8a1c16f2008-12-17 15:59:43 +00001949//////////////////////////////////////////////////////////////////////////////
1950// These are the virtual drawing methods
1951//////////////////////////////////////////////////////////////////////////////
1952
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001953void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001954 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001955 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1956 }
1957}
1958
reed41af9662015-01-05 07:49:08 -08001959void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001960 this->internalDrawPaint(paint);
1961}
1962
1963void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001964 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001965
1966 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001967 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001968 }
1969
reed@google.com4e2b3d32011-04-07 14:18:59 +00001970 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001971}
1972
reed41af9662015-01-05 07:49:08 -08001973void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1974 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001975 if ((long)count <= 0) {
1976 return;
1977 }
1978
Mike Reed822128b2017-02-28 16:41:03 -05001979 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001980 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001981 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001982 // special-case 2 points (common for drawing a single line)
1983 if (2 == count) {
1984 r.set(pts[0], pts[1]);
1985 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001986 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001987 }
Mike Reed822128b2017-02-28 16:41:03 -05001988 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001989 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1990 return;
1991 }
1992 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001993 }
reed@google.coma584aed2012-05-16 14:06:02 +00001994
halcanary96fcdcc2015-08-27 07:41:13 -07001995 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001996
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001997 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001998
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002000 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002001 }
reed@google.com4b226022011-01-11 18:32:13 +00002002
reed@google.com4e2b3d32011-04-07 14:18:59 +00002003 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004}
2005
reed4a167172016-08-18 17:15:25 -07002006static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2007 return ((intptr_t)paint.getImageFilter() |
2008#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2009 (intptr_t)canvas->getDrawFilter() |
2010#endif
2011 (intptr_t)paint.getLooper() ) != 0;
2012}
2013
reed41af9662015-01-05 07:49:08 -08002014void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002015 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002016 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002017 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002018 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002019 return;
2020 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002021 }
reed@google.com4b226022011-01-11 18:32:13 +00002022
reed4a167172016-08-18 17:15:25 -07002023 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002024 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002025
reed4a167172016-08-18 17:15:25 -07002026 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002027 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002028 }
2029
2030 LOOPER_END
2031 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002032 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002033 SkDrawIter iter(this);
2034 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002035 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002036 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002037 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002038}
2039
msarett44df6512016-08-25 13:54:30 -07002040void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002041 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002042 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002043 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002044 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2045 return;
2046 }
msarett44df6512016-08-25 13:54:30 -07002047 }
2048
Mike Reed822128b2017-02-28 16:41:03 -05002049 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002050
2051 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002052 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002053 }
2054
2055 LOOPER_END
2056}
2057
reed41af9662015-01-05 07:49:08 -08002058void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002059 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002060 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002061 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002062 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002063 return;
2064 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002065 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002066
Mike Reed822128b2017-02-28 16:41:03 -05002067 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002068
2069 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002070 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002071 }
2072
2073 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002074}
2075
bsalomonac3aa242016-08-19 11:25:19 -07002076void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2077 SkScalar sweepAngle, bool useCenter,
2078 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002079 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002080 if (paint.canComputeFastBounds()) {
2081 SkRect storage;
2082 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002083 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002084 return;
2085 }
bsalomonac3aa242016-08-19 11:25:19 -07002086 }
2087
Mike Reed822128b2017-02-28 16:41:03 -05002088 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002089
2090 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002091 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002092 }
2093
2094 LOOPER_END
2095}
2096
reed41af9662015-01-05 07:49:08 -08002097void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002098 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002099 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002100 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2101 return;
2102 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002103 }
2104
2105 if (rrect.isRect()) {
2106 // call the non-virtual version
2107 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002108 return;
2109 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002110 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002111 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2112 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002113 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002114
Mike Reed822128b2017-02-28 16:41:03 -05002115 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002116
2117 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002118 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002119 }
2120
2121 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002122}
2123
Mike Reed822128b2017-02-28 16:41:03 -05002124void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002125 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002126 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002127 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2128 return;
2129 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002130 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002131
Mike Reed822128b2017-02-28 16:41:03 -05002132 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002133
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002134 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002135 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002136 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002137
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002138 LOOPER_END
2139}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002140
reed41af9662015-01-05 07:49:08 -08002141void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002142 if (!path.isFinite()) {
2143 return;
2144 }
2145
Mike Reed822128b2017-02-28 16:41:03 -05002146 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002147 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002148 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002149 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2150 return;
2151 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002152 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002153
Mike Reed822128b2017-02-28 16:41:03 -05002154 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002155 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002156 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002157 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002158 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002159 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002160
Mike Reed822128b2017-02-28 16:41:03 -05002161 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002162
2163 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002164 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002165 }
2166
reed@google.com4e2b3d32011-04-07 14:18:59 +00002167 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002168}
2169
reed262a71b2015-12-05 13:07:27 -08002170bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002171 if (!paint.getImageFilter()) {
2172 return false;
2173 }
2174
2175 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002176 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002177 return false;
2178 }
2179
2180 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2181 // Once we can filter and the filter will return a result larger than itself, we should be
2182 // able to remove this constraint.
2183 // skbug.com/4526
2184 //
2185 SkPoint pt;
2186 ctm.mapXY(x, y, &pt);
2187 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2188 return ir.contains(fMCRec->fRasterClip.getBounds());
2189}
2190
reeda85d4d02015-05-06 12:56:48 -07002191void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07002192 SkRect bounds = SkRect::MakeXYWH(x, y,
2193 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002194 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002195 SkRect tmp = bounds;
2196 if (paint) {
2197 paint->computeFastBounds(tmp, &tmp);
2198 }
2199 if (this->quickReject(tmp)) {
2200 return;
2201 }
reeda85d4d02015-05-06 12:56:48 -07002202 }
halcanary9d524f22016-03-29 09:03:52 -07002203
reeda85d4d02015-05-06 12:56:48 -07002204 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002205 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002206 paint = lazy.init();
2207 }
reed262a71b2015-12-05 13:07:27 -08002208
reeda2217ef2016-07-20 06:04:34 -07002209 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002210 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2211 *paint);
2212 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002213 special = this->getDevice()->makeSpecial(image);
2214 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002215 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002216 }
2217 }
2218
reed262a71b2015-12-05 13:07:27 -08002219 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2220
reeda85d4d02015-05-06 12:56:48 -07002221 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002222 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002223 if (special) {
2224 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002225 iter.fDevice->ctm().mapXY(x, y, &pt);
2226 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002227 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002228 SkScalarRoundToInt(pt.fY), pnt,
2229 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002230 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002231 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002232 }
reeda85d4d02015-05-06 12:56:48 -07002233 }
halcanary9d524f22016-03-29 09:03:52 -07002234
reeda85d4d02015-05-06 12:56:48 -07002235 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002236}
2237
reed41af9662015-01-05 07:49:08 -08002238void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002239 const SkPaint* paint, SrcRectConstraint constraint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002240 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002241 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002242 if (paint) {
2243 paint->computeFastBounds(dst, &storage);
2244 }
2245 if (this->quickReject(storage)) {
2246 return;
2247 }
reeda85d4d02015-05-06 12:56:48 -07002248 }
2249 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002250 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002251 paint = lazy.init();
2252 }
halcanary9d524f22016-03-29 09:03:52 -07002253
senorblancoc41e7e12015-12-07 12:51:30 -08002254 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002255 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002256
reeda85d4d02015-05-06 12:56:48 -07002257 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002258 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002259 }
halcanary9d524f22016-03-29 09:03:52 -07002260
reeda85d4d02015-05-06 12:56:48 -07002261 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002262}
2263
reed41af9662015-01-05 07:49:08 -08002264void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002265 SkDEBUGCODE(bitmap.validate();)
2266
reed33366972015-10-08 09:22:02 -07002267 if (bitmap.drawsNothing()) {
2268 return;
2269 }
2270
2271 SkLazyPaint lazy;
2272 if (nullptr == paint) {
2273 paint = lazy.init();
2274 }
2275
Mike Reed822128b2017-02-28 16:41:03 -05002276 SkRect bounds;
2277 bitmap.getBounds(&bounds);
2278 bounds.offset(x, y);
2279 bool canFastBounds = paint->canComputeFastBounds();
2280 if (canFastBounds) {
2281 SkRect storage;
2282 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002283 return;
2284 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002285 }
reed@google.com4b226022011-01-11 18:32:13 +00002286
reeda2217ef2016-07-20 06:04:34 -07002287 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002288 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2289 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002290 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002291 special = this->getDevice()->makeSpecial(bitmap);
2292 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002293 drawAsSprite = false;
2294 }
2295 }
2296
Mike Reed822128b2017-02-28 16:41:03 -05002297 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002298
2299 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002300 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002301 if (special) {
reed262a71b2015-12-05 13:07:27 -08002302 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002303 iter.fDevice->ctm().mapXY(x, y, &pt);
2304 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002305 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002306 SkScalarRoundToInt(pt.fY), pnt,
2307 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002308 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002309 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002310 }
reed33366972015-10-08 09:22:02 -07002311 }
msarettfbfa2582016-08-12 08:29:08 -07002312
reed33366972015-10-08 09:22:02 -07002313 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002314}
2315
reed@google.com9987ec32011-09-07 11:57:52 +00002316// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002317void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002318 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002319 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002320 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002321 return;
2322 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002323
halcanary96fcdcc2015-08-27 07:41:13 -07002324 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002325 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002326 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2327 return;
2328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002329 }
reed@google.com3d608122011-11-21 15:16:16 +00002330
reed@google.com33535f32012-09-25 15:37:50 +00002331 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002332 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002333 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002334 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002335
senorblancoc41e7e12015-12-07 12:51:30 -08002336 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002337 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002338
reed@google.com33535f32012-09-25 15:37:50 +00002339 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002340 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002341 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002342
reed@google.com33535f32012-09-25 15:37:50 +00002343 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002344}
2345
reed41af9662015-01-05 07:49:08 -08002346void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002347 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002348 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002349 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002350}
2351
reed4c21dc52015-06-25 12:32:03 -07002352void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2353 const SkPaint* paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002354 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002355 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002356 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2357 return;
2358 }
reed@google.com3d608122011-11-21 15:16:16 +00002359 }
halcanary9d524f22016-03-29 09:03:52 -07002360
reed4c21dc52015-06-25 12:32:03 -07002361 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002362 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002363 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002364 }
halcanary9d524f22016-03-29 09:03:52 -07002365
senorblancoc41e7e12015-12-07 12:51:30 -08002366 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002367
reed4c21dc52015-06-25 12:32:03 -07002368 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002369 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002370 }
halcanary9d524f22016-03-29 09:03:52 -07002371
reed4c21dc52015-06-25 12:32:03 -07002372 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002373}
2374
reed41af9662015-01-05 07:49:08 -08002375void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2376 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002377 SkDEBUGCODE(bitmap.validate();)
2378
halcanary96fcdcc2015-08-27 07:41:13 -07002379 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002380 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002381 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2382 return;
2383 }
reed4c21dc52015-06-25 12:32:03 -07002384 }
halcanary9d524f22016-03-29 09:03:52 -07002385
reed4c21dc52015-06-25 12:32:03 -07002386 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002387 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002388 paint = lazy.init();
2389 }
halcanary9d524f22016-03-29 09:03:52 -07002390
senorblancoc41e7e12015-12-07 12:51:30 -08002391 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002392
reed4c21dc52015-06-25 12:32:03 -07002393 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002394 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002395 }
halcanary9d524f22016-03-29 09:03:52 -07002396
reed4c21dc52015-06-25 12:32:03 -07002397 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002398}
2399
msarett16882062016-08-16 09:31:08 -07002400void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2401 const SkPaint* paint) {
2402 if (nullptr == paint || paint->canComputeFastBounds()) {
2403 SkRect storage;
2404 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2405 return;
2406 }
2407 }
2408
2409 SkLazyPaint lazy;
2410 if (nullptr == paint) {
2411 paint = lazy.init();
2412 }
2413
2414 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2415
2416 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002417 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002418 }
2419
2420 LOOPER_END
2421}
2422
2423void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2424 const SkRect& dst, const SkPaint* paint) {
2425 if (nullptr == paint || paint->canComputeFastBounds()) {
2426 SkRect storage;
2427 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2428 return;
2429 }
2430 }
2431
2432 SkLazyPaint lazy;
2433 if (nullptr == paint) {
2434 paint = lazy.init();
2435 }
2436
2437 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2438
2439 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002440 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002441 }
2442
2443 LOOPER_END
2444}
2445
reed@google.comf67e4cf2011-03-15 20:56:58 +00002446class SkDeviceFilteredPaint {
2447public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002448 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002449 uint32_t filteredFlags = device->filterTextFlags(paint);
2450 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002451 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002452 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002453 fPaint = newPaint;
2454 } else {
2455 fPaint = &paint;
2456 }
2457 }
2458
reed@google.comf67e4cf2011-03-15 20:56:58 +00002459 const SkPaint& paint() const { return *fPaint; }
2460
2461private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002462 const SkPaint* fPaint;
2463 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002464};
2465
reed@google.come0d9ce82014-04-23 04:00:17 +00002466void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2467 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002468 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002469
2470 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002471 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002472 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473 }
2474
reed@google.com4e2b3d32011-04-07 14:18:59 +00002475 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476}
2477
reed@google.come0d9ce82014-04-23 04:00:17 +00002478void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2479 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002480 SkPoint textOffset = SkPoint::Make(0, 0);
2481
halcanary96fcdcc2015-08-27 07:41:13 -07002482 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002483
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002485 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002486 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002487 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002489
reed@google.com4e2b3d32011-04-07 14:18:59 +00002490 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002491}
2492
reed@google.come0d9ce82014-04-23 04:00:17 +00002493void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2494 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002495
2496 SkPoint textOffset = SkPoint::Make(0, constY);
2497
halcanary96fcdcc2015-08-27 07:41:13 -07002498 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002499
reed@android.com8a1c16f2008-12-17 15:59:43 +00002500 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002501 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002502 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002503 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002504 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002505
reed@google.com4e2b3d32011-04-07 14:18:59 +00002506 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002507}
2508
reed@google.come0d9ce82014-04-23 04:00:17 +00002509void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2510 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002511 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002512
reed@android.com8a1c16f2008-12-17 15:59:43 +00002513 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002514 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002515 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002516 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002517
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002518 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002519}
2520
reed45561a02016-07-07 12:47:17 -07002521void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2522 const SkRect* cullRect, const SkPaint& paint) {
2523 if (cullRect && this->quickReject(*cullRect)) {
2524 return;
2525 }
2526
2527 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2528
2529 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002530 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002531 }
2532
2533 LOOPER_END
2534}
2535
fmalita00d5c2c2014-08-21 08:53:26 -07002536void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2537 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002538
fmalita85d5eb92015-03-04 11:20:12 -08002539 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002540 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002541 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002542 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002543 SkRect tmp;
2544 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2545 return;
2546 }
2547 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002548 }
2549
fmalita024f9962015-03-03 19:08:17 -08002550 // We cannot filter in the looper as we normally do, because the paint is
2551 // incomplete at this point (text-related attributes are embedded within blob run paints).
2552 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002553 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002554
fmalita85d5eb92015-03-04 11:20:12 -08002555 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002556
fmalitaaa1b9122014-08-28 14:32:24 -07002557 while (iter.next()) {
2558 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002559 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002560 }
2561
fmalitaaa1b9122014-08-28 14:32:24 -07002562 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002563
2564 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002565}
2566
Cary Clark2a475ea2017-04-28 15:35:12 -04002567void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2568 this->drawText(string.c_str(), string.size(), x, y, paint);
2569}
2570
reed@google.come0d9ce82014-04-23 04:00:17 +00002571// These will become non-virtual, so they always call the (virtual) onDraw... method
2572void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2573 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002574 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002575 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002576 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002577 this->onDrawText(text, byteLength, x, y, paint);
2578 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002579}
2580void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2581 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002582 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002583 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002584 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002585 this->onDrawPosText(text, byteLength, pos, paint);
2586 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002587}
2588void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2589 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002590 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002591 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002592 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002593 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2594 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002595}
2596void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2597 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002598 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002599 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002600 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002601 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2602 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002603}
reed45561a02016-07-07 12:47:17 -07002604void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2605 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002606 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002607 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002608 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002609 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2610 }
2611}
fmalita00d5c2c2014-08-21 08:53:26 -07002612void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2613 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002614 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002615 RETURN_ON_NULL(blob);
reede3b38ce2016-01-08 09:18:44 -08002616 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002617}
reed@google.come0d9ce82014-04-23 04:00:17 +00002618
Mike Reede88a1cb2017-03-17 09:50:46 -04002619void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2620 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002621 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2622
2623 while (iter.next()) {
2624 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002625 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002626 }
2627
2628 LOOPER_END
2629}
2630
dandovb3c9d1c2014-08-12 08:34:29 -07002631void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002632 const SkPoint texCoords[4], SkBlendMode bmode,
2633 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002634 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002635 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002636 return;
2637 }
mtklein6cfa73a2014-08-13 13:33:49 -07002638
Mike Reedfaba3712016-11-03 14:45:31 -04002639 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002640}
2641
2642void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002643 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002644 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002645 // Since a patch is always within the convex hull of the control points, we discard it when its
2646 // bounding rectangle is completely outside the current clip.
2647 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002648 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002649 if (this->quickReject(bounds)) {
2650 return;
2651 }
mtklein6cfa73a2014-08-13 13:33:49 -07002652
Mike Reed435071e2017-05-23 11:22:56 -04002653 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2654
halcanary96fcdcc2015-08-27 07:41:13 -07002655 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002656
dandovecfff212014-08-04 10:02:00 -07002657 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002658 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002659 }
mtklein6cfa73a2014-08-13 13:33:49 -07002660
dandovecfff212014-08-04 10:02:00 -07002661 LOOPER_END
2662}
2663
reeda8db7282015-07-07 10:22:31 -07002664void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002665#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002666 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002667#endif
reede3b38ce2016-01-08 09:18:44 -08002668 RETURN_ON_NULL(dr);
2669 if (x || y) {
2670 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2671 this->onDrawDrawable(dr, &matrix);
2672 } else {
2673 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002674 }
2675}
2676
reeda8db7282015-07-07 10:22:31 -07002677void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002678#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002679 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002680#endif
reede3b38ce2016-01-08 09:18:44 -08002681 RETURN_ON_NULL(dr);
2682 if (matrix && matrix->isIdentity()) {
2683 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002684 }
reede3b38ce2016-01-08 09:18:44 -08002685 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002686}
2687
2688void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002689 // drawable bounds are no longer reliable (e.g. android displaylist)
2690 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002691 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002692}
2693
reed71c3c762015-06-24 10:29:17 -07002694void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002695 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002696 const SkRect* cull, const SkPaint* paint) {
2697 if (cull && this->quickReject(*cull)) {
2698 return;
2699 }
2700
2701 SkPaint pnt;
2702 if (paint) {
2703 pnt = *paint;
2704 }
halcanary9d524f22016-03-29 09:03:52 -07002705
halcanary96fcdcc2015-08-27 07:41:13 -07002706 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002707 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002708 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002709 }
2710 LOOPER_END
2711}
2712
reedf70b5312016-03-04 16:36:20 -08002713void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2714 SkASSERT(key);
2715
2716 SkPaint paint;
2717 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2718 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002719 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002720 }
2721 LOOPER_END
2722}
2723
reed@android.com8a1c16f2008-12-17 15:59:43 +00002724//////////////////////////////////////////////////////////////////////////////
2725// These methods are NOT virtual, and therefore must call back into virtual
2726// methods, rather than actually drawing themselves.
2727//////////////////////////////////////////////////////////////////////////////
2728
reed374772b2016-10-05 17:33:02 -07002729void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002731 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002732 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002733 this->drawPaint(paint);
2734}
2735
2736void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002737 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002738 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2739}
2740
Mike Reed3661bc92017-02-22 13:21:42 -05002741void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002743 pts[0].set(x0, y0);
2744 pts[1].set(x1, y1);
2745 this->drawPoints(kLines_PointMode, 2, pts, paint);
2746}
2747
Mike Reed3661bc92017-02-22 13:21:42 -05002748void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002749 if (radius < 0) {
2750 radius = 0;
2751 }
2752
2753 SkRect r;
2754 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002755 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002756}
2757
2758void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2759 const SkPaint& paint) {
2760 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002761 SkRRect rrect;
2762 rrect.setRectXY(r, rx, ry);
2763 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764 } else {
2765 this->drawRect(r, paint);
2766 }
2767}
2768
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2770 SkScalar sweepAngle, bool useCenter,
2771 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002772 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002773 if (oval.isEmpty() || !sweepAngle) {
2774 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775 }
bsalomon21af9ca2016-08-25 12:29:23 -07002776 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777}
2778
2779void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2780 const SkPath& path, SkScalar hOffset,
2781 SkScalar vOffset, const SkPaint& paint) {
2782 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002783
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784 matrix.setTranslate(hOffset, vOffset);
2785 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2786}
2787
reed@android.comf76bacf2009-05-13 14:00:33 +00002788///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002789
2790/**
2791 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2792 * against the playback cost of recursing into the subpicture to get at its actual ops.
2793 *
2794 * For now we pick a conservatively small value, though measurement (and other heuristics like
2795 * the type of ops contained) may justify changing this value.
2796 */
2797#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002798
reedd5fa1a42014-08-09 11:08:05 -07002799void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002800 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002801 RETURN_ON_NULL(picture);
2802
reede3b38ce2016-01-08 09:18:44 -08002803 if (matrix && matrix->isIdentity()) {
2804 matrix = nullptr;
2805 }
2806 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2807 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2808 picture->playback(this);
2809 } else {
2810 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002811 }
2812}
robertphillips9b14f262014-06-04 05:40:44 -07002813
reedd5fa1a42014-08-09 11:08:05 -07002814void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2815 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002816 if (!paint || paint->canComputeFastBounds()) {
2817 SkRect bounds = picture->cullRect();
2818 if (paint) {
2819 paint->computeFastBounds(bounds, &bounds);
2820 }
2821 if (matrix) {
2822 matrix->mapRect(&bounds);
2823 }
2824 if (this->quickReject(bounds)) {
2825 return;
2826 }
2827 }
2828
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002829 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002830 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831}
2832
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833///////////////////////////////////////////////////////////////////////////////
2834///////////////////////////////////////////////////////////////////////////////
2835
reed3aafe112016-08-18 12:45:34 -07002836SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002837 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002838
2839 SkASSERT(canvas);
2840
reed3aafe112016-08-18 12:45:34 -07002841 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842 fDone = !fImpl->next();
2843}
2844
2845SkCanvas::LayerIter::~LayerIter() {
2846 fImpl->~SkDrawIter();
2847}
2848
2849void SkCanvas::LayerIter::next() {
2850 fDone = !fImpl->next();
2851}
2852
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002853SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002854 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002855}
2856
2857const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002858 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002859}
2860
2861const SkPaint& SkCanvas::LayerIter::paint() const {
2862 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002863 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002864 paint = &fDefaultPaint;
2865 }
2866 return *paint;
2867}
2868
Mike Reeda1361362017-03-07 09:37:29 -05002869void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2870 return fImpl->fDevice->onAsRgnClip(rgn);
2871}
2872
reed@android.com8a1c16f2008-12-17 15:59:43 +00002873int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2874int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002875
2876///////////////////////////////////////////////////////////////////////////////
2877
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002878static bool supported_for_raster_canvas(const SkImageInfo& info) {
2879 switch (info.alphaType()) {
2880 case kPremul_SkAlphaType:
2881 case kOpaque_SkAlphaType:
2882 break;
2883 default:
2884 return false;
2885 }
2886
2887 switch (info.colorType()) {
2888 case kAlpha_8_SkColorType:
2889 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002890 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002891 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002892 break;
2893 default:
2894 return false;
2895 }
2896
2897 return true;
2898}
2899
Mike Reed5df49342016-11-12 08:06:55 -06002900std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002901 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002902 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002903 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002904 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002905
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002906 SkBitmap bitmap;
2907 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002908 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002909 }
Mike Reed12f77342017-11-08 11:19:52 -05002910
2911 return props ?
2912 skstd::make_unique<SkCanvas>(bitmap, *props) :
2913 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002914}
reedd5fa1a42014-08-09 11:08:05 -07002915
2916///////////////////////////////////////////////////////////////////////////////
2917
Florin Malitaee424ac2016-12-01 12:47:59 -05002918SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2919 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2920
Florin Malita439ace92016-12-02 12:05:41 -05002921SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2922 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2923
Florin Malitaee424ac2016-12-01 12:47:59 -05002924SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2925 (void)this->INHERITED::getSaveLayerStrategy(rec);
2926 return kNoLayer_SaveLayerStrategy;
2927}
2928
2929///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002930
reed73603f32016-09-20 08:42:38 -07002931static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2932static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2933static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2934static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2935static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2936static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002937
2938///////////////////////////////////////////////////////////////////////////////////////////////////
2939
2940SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2941 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002942 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002943 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2944 SkIPoint origin = dev->getOrigin();
2945 SkMatrix ctm = this->getTotalMatrix();
2946 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2947
2948 SkIRect clip = fMCRec->fRasterClip.getBounds();
2949 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002950 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002951 clip.setEmpty();
2952 }
2953
2954 fAllocator->updateHandle(handle, ctm, clip);
2955 return handle;
2956 }
2957 return nullptr;
2958}
2959
2960static bool install(SkBitmap* bm, const SkImageInfo& info,
2961 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002962 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002963}
2964
2965SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2966 SkBitmap* bm) {
2967 SkRasterHandleAllocator::Rec rec;
2968 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2969 return nullptr;
2970 }
2971 return rec.fHandle;
2972}
2973
2974std::unique_ptr<SkCanvas>
2975SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2976 const SkImageInfo& info, const Rec* rec) {
2977 if (!alloc || !supported_for_raster_canvas(info)) {
2978 return nullptr;
2979 }
2980
2981 SkBitmap bm;
2982 Handle hndl;
2983
2984 if (rec) {
2985 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2986 } else {
2987 hndl = alloc->allocBitmap(info, &bm);
2988 }
2989 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2990}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002991
2992///////////////////////////////////////////////////////////////////////////////////////////////////
2993
2994