blob: f339338f0c9016d0d5cc5d4bf4fe9383d0347012 [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"
Florin Malitaee424ac2016-12-01 12:47:59 -050026#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070027#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070028#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070029#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000030#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070031#include "SkRadialShadowMapShader.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"
vjiaoblack904527d2016-08-09 09:32:09 -070035#include "SkShadowPaintFilterCanvas.h"
36#include "SkShadowShader.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040038#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000039#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070040#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000041#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000042#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080043#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070044#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000045
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000046#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080047#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#include "GrRenderTarget.h"
Brian Osman3b655982017-03-07 16:58:08 -050049#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070050
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050052#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050053#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000054
reede3b38ce2016-01-08 09:18:44 -080055#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
56
Mike Reed139e5e02017-03-08 11:29:33 -050057class SkNoPixelsDevice : public SkBaseDevice {
58public:
59 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
60 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
Mike Reed566e53c2017-03-10 10:49:45 -050061 {
Mike Reede393a622017-03-10 16:35:25 -050062 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
63 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050064 }
Mike Reed139e5e02017-03-08 11:29:33 -050065
66 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050067 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050068 this->privateResize(bounds.width(), bounds.height());
69 }
70
71protected:
72 // We don't track the clip at all (for performance), but we have to respond to some queries.
73 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
74 void onSave() override {}
75 void onRestore() override {}
76 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
77 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
78 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
79 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
80 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
81 bool onClipIsAA() const override { return false; }
82 void onAsRgnClip(SkRegion* rgn) const override {
83 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
84 }
85 ClipType onGetClipType() const override {
86 return kRect_ClipType;
87 }
88
89 void drawPaint(const SkPaint& paint) override {}
90 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
91 void drawRect(const SkRect&, const SkPaint&) override {}
92 void drawOval(const SkRect&, const SkPaint&) override {}
93 void drawRRect(const SkRRect&, const SkPaint&) override {}
94 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
95 void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {}
96 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
97 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
98 SkCanvas::SrcRectConstraint) override {}
99 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
100 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
101 const SkPaint&) override {}
102 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
Mike Reed2f6b5a42017-03-19 15:04:17 -0400103 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -0500104
105private:
106 typedef SkBaseDevice INHERITED;
107};
108
109///////////////////////////////////////////////////////////////////////////////////////////////////
110
reedc83a2972015-07-16 07:40:45 -0700111/*
112 * Return true if the drawing this rect would hit every pixels in the canvas.
113 *
114 * Returns false if
115 * - rect does not contain the canvas' bounds
116 * - paint is not fill
117 * - paint would blur or otherwise change the coverage of the rect
118 */
119bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
120 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700121 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
122 (int)kNone_ShaderOverrideOpacity,
123 "need_matching_enums0");
124 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
125 (int)kOpaque_ShaderOverrideOpacity,
126 "need_matching_enums1");
127 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
128 (int)kNotOpaque_ShaderOverrideOpacity,
129 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700130
131 const SkISize size = this->getBaseLayerSize();
132 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500133
134 // if we're clipped at all, we can't overwrite the entire surface
135 {
136 SkBaseDevice* base = this->getDevice();
137 SkBaseDevice* top = this->getTopDevice();
138 if (base != top) {
139 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
140 }
141 if (!base->clipIsWideOpen()) {
142 return false;
143 }
reedc83a2972015-07-16 07:40:45 -0700144 }
145
146 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700147 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700148 return false; // conservative
149 }
halcanaryc5769b22016-08-10 07:13:21 -0700150
151 SkRect devRect;
152 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
153 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700154 return false;
155 }
156 }
157
158 if (paint) {
159 SkPaint::Style paintStyle = paint->getStyle();
160 if (!(paintStyle == SkPaint::kFill_Style ||
161 paintStyle == SkPaint::kStrokeAndFill_Style)) {
162 return false;
163 }
164 if (paint->getMaskFilter() || paint->getLooper()
165 || paint->getPathEffect() || paint->getImageFilter()) {
166 return false; // conservative
167 }
168 }
169 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
170}
171
172///////////////////////////////////////////////////////////////////////////////////////////////////
173
reedd990e2f2014-12-22 11:58:30 -0800174static bool gIgnoreSaveLayerBounds;
175void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
176 gIgnoreSaveLayerBounds = ignore;
177}
178bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
179 return gIgnoreSaveLayerBounds;
180}
181
reed0acf1b42014-12-22 16:12:38 -0800182static bool gTreatSpriteAsBitmap;
183void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
184 gTreatSpriteAsBitmap = spriteAsBitmap;
185}
186bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
187 return gTreatSpriteAsBitmap;
188}
189
reed@google.comda17f752012-08-16 18:27:05 +0000190// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191//#define SK_TRACE_SAVERESTORE
192
193#ifdef SK_TRACE_SAVERESTORE
194 static int gLayerCounter;
195 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
196 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
197
198 static int gRecCounter;
199 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
200 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
201
202 static int gCanvasCounter;
203 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
204 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
205#else
206 #define inc_layer()
207 #define dec_layer()
208 #define inc_rec()
209 #define dec_rec()
210 #define inc_canvas()
211 #define dec_canvas()
212#endif
213
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000214typedef SkTLazy<SkPaint> SkLazyPaint;
215
reedc83a2972015-07-16 07:40:45 -0700216void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000217 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700218 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
219 ? SkSurface::kDiscard_ContentChangeMode
220 : SkSurface::kRetain_ContentChangeMode);
221 }
222}
223
224void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
225 ShaderOverrideOpacity overrideOpacity) {
226 if (fSurfaceBase) {
227 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
228 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
229 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
230 // and therefore we don't care which mode we're in.
231 //
232 if (fSurfaceBase->outstandingImageSnapshot()) {
233 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
234 mode = SkSurface::kDiscard_ContentChangeMode;
235 }
236 }
237 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000238 }
239}
240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000243/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 The clip/matrix/proc are fields that reflect the top of the save/restore
245 stack. Whenever the canvas changes, it marks a dirty flag, and then before
246 these are used (assuming we're not on a layer) we rebuild these cache
247 values: they reflect the top of the save stack, but translated and clipped
248 by the device's XY offset and bitmap-bounds.
249*/
250struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400251 DeviceCM* fNext;
252 sk_sp<SkBaseDevice> fDevice;
253 SkRasterClip fClip;
254 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
255 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256
Florin Malita713b8ef2017-04-28 10:57:24 -0400257 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed)
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)
Florin Malita713b8ef2017-04-28 10:57:24 -0400262 {}
reed@google.com4b226022011-01-11 18:32:13 +0000263
mtkleinfeaadee2015-04-08 11:25:48 -0700264 void reset(const SkIRect& bounds) {
265 SkASSERT(!fPaint);
266 SkASSERT(!fNext);
267 SkASSERT(fDevice);
268 fClip.setRect(bounds);
269 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270};
271
272/* This is the record we keep for each save/restore level in the stack.
273 Since a level optionally copies the matrix and/or stack, we have pointers
274 for these fields. If the value is copied for this level, the copy is
275 stored in the ...Storage field, and the pointer points to that. If the
276 value is not copied for this level, we ignore ...Storage, and just point
277 at the corresponding value in the previous level in the stack.
278*/
279class SkCanvas::MCRec {
280public:
reed1f836ee2014-07-07 07:49:34 -0700281 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700282 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 /* If there are any layers in the stack, this points to the top-most
284 one that is at or below this level in the stack (so we know what
285 bitmap/device to draw into from this level. This value is NOT
286 reference counted, since the real owner is either our fLayer field,
287 or a previous one in a lower level.)
288 */
Mike Reeda1361362017-03-07 09:37:29 -0500289 DeviceCM* fTopLayer;
290 SkConservativeClip fRasterClip;
291 SkMatrix fMatrix;
292 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293
vjiaoblacke5de1302016-07-13 14:05:28 -0700294 // This is the current cumulative depth (aggregate of all done translateZ calls)
295 SkScalar fCurDrawDepth;
296
Mike Reeda1361362017-03-07 09:37:29 -0500297 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700298 fFilter = nullptr;
299 fLayer = nullptr;
300 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800301 fMatrix.reset();
302 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700303 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700304
reedd9544982014-09-09 18:46:22 -0700305 // don't bother initializing fNext
306 inc_rec();
307 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700308 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
309 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700310 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700311 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700312 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800313 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700314
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315 // don't bother initializing fNext
316 inc_rec();
317 }
318 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000319 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700320 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321 dec_rec();
322 }
mtkleinfeaadee2015-04-08 11:25:48 -0700323
324 void reset(const SkIRect& bounds) {
325 SkASSERT(fLayer);
326 SkASSERT(fDeferredSaveCount == 0);
327
328 fMatrix.reset();
329 fRasterClip.setRect(bounds);
330 fLayer->reset(bounds);
331 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332};
333
Mike Reeda1361362017-03-07 09:37:29 -0500334class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335public:
Mike Reeda1361362017-03-07 09:37:29 -0500336 SkDrawIter(SkCanvas* canvas)
337 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
338 {}
reed@google.com4b226022011-01-11 18:32:13 +0000339
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000341 const DeviceCM* rec = fCurrLayer;
342 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400343 fDevice = rec->fDevice.get();
344 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700346 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347 return true;
348 }
349 return false;
350 }
reed@google.com4b226022011-01-11 18:32:13 +0000351
reed@google.com6f8f2922011-03-04 22:27:10 +0000352 int getX() const { return fDevice->getOrigin().x(); }
353 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000355
Mike Reed99330ba2017-02-22 11:01:08 -0500356 SkBaseDevice* fDevice;
357
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 const DeviceCM* fCurrLayer;
360 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361};
362
Florin Malita713b8ef2017-04-28 10:57:24 -0400363#define FOR_EACH_TOP_DEVICE( code ) \
364 do { \
365 DeviceCM* layer = fMCRec->fTopLayer; \
366 while (layer) { \
367 SkBaseDevice* device = layer->fDevice.get(); \
368 if (device) { \
369 code; \
370 } \
371 layer = layer->fNext; \
372 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500373 } while (0)
374
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375/////////////////////////////////////////////////////////////////////////////
376
reeddbc3cef2015-04-29 12:18:57 -0700377static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
378 return lazy->isValid() ? lazy->get() : lazy->set(orig);
379}
380
381/**
382 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700383 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700384 */
reedd053ce92016-03-22 10:17:23 -0700385static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700386 SkImageFilter* imgf = paint.getImageFilter();
387 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700388 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700389 }
390
reedd053ce92016-03-22 10:17:23 -0700391 SkColorFilter* imgCFPtr;
392 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700393 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700394 }
reedd053ce92016-03-22 10:17:23 -0700395 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700396
397 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700398 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700399 // there is no existing paint colorfilter, so we can just return the imagefilter's
400 return imgCF;
401 }
402
403 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
404 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700405 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700406}
407
senorblanco87e066e2015-10-28 11:23:36 -0700408/**
409 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
410 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
411 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
412 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
413 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
414 * conservative "effective" bounds based on the settings in the paint... with one exception. This
415 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
416 * deliberately ignored.
417 */
418static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
419 const SkRect& rawBounds,
420 SkRect* storage) {
421 SkPaint tmpUnfiltered(paint);
422 tmpUnfiltered.setImageFilter(nullptr);
423 if (tmpUnfiltered.canComputeFastBounds()) {
424 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
425 } else {
426 return rawBounds;
427 }
428}
429
reed@android.com8a1c16f2008-12-17 15:59:43 +0000430class AutoDrawLooper {
431public:
senorblanco87e066e2015-10-28 11:23:36 -0700432 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
433 // paint. It's used to determine the size of the offscreen layer for filters.
434 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700435 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700436 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000437 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800438#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800440#else
441 fFilter = nullptr;
442#endif
reed4a8126e2014-09-22 07:29:03 -0700443 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000444 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700445 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000446 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447
reedd053ce92016-03-22 10:17:23 -0700448 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700449 if (simplifiedCF) {
450 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700451 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700452 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700453 fPaint = paint;
454 }
455
456 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700457 /**
458 * We implement ImageFilters for a given draw by creating a layer, then applying the
459 * imagefilter to the pixels of that layer (its backing surface/image), and then
460 * we call restore() to xfer that layer to the main canvas.
461 *
462 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
463 * 2. Generate the src pixels:
464 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
465 * return (fPaint). We then draw the primitive (using srcover) into a cleared
466 * buffer/surface.
467 * 3. Restore the layer created in #1
468 * The imagefilter is passed the buffer/surface from the layer (now filled with the
469 * src pixels of the primitive). It returns a new "filtered" buffer, which we
470 * draw onto the previous layer using the xfermode from the original paint.
471 */
reed@google.com8926b162012-03-23 15:36:36 +0000472 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500473 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700474 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700475 SkRect storage;
476 if (rawBounds) {
477 // Make rawBounds include all paint outsets except for those due to image filters.
478 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
479 }
reedbfd5f172016-01-07 11:28:08 -0800480 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700481 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700482 fTempLayerForImageFilter = true;
483 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000484 }
485
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000486 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500487 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000488 fIsSimple = false;
489 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700490 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000491 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700492 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000493 }
494 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000495
reed@android.com8a1c16f2008-12-17 15:59:43 +0000496 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700497 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000498 fCanvas->internalRestore();
499 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000500 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000502
reed@google.com4e2b3d32011-04-07 14:18:59 +0000503 const SkPaint& paint() const {
504 SkASSERT(fPaint);
505 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000507
reed@google.com129ec222012-05-15 13:24:09 +0000508 bool next(SkDrawFilter::Type drawType) {
509 if (fDone) {
510 return false;
511 } else if (fIsSimple) {
512 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000513 return !fPaint->nothingToDraw();
514 } else {
515 return this->doNext(drawType);
516 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000517 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000518
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500520 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700521 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000522 SkCanvas* fCanvas;
523 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000524 SkDrawFilter* fFilter;
525 const SkPaint* fPaint;
526 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700527 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000528 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000529 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000530 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500531 char fStorage[48];
532 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000533
534 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535};
536
reed@google.com129ec222012-05-15 13:24:09 +0000537bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700538 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000539 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700540 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000541
reeddbc3cef2015-04-29 12:18:57 -0700542 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
543 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000544
reed5c476fb2015-04-20 08:04:21 -0700545 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700546 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700547 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000548 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000549
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000550 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000551 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000552 return false;
553 }
554 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000555 if (!fFilter->filter(paint, drawType)) {
556 fDone = true;
557 return false;
558 }
halcanary96fcdcc2015-08-27 07:41:13 -0700559 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000560 // no looper means we only draw once
561 fDone = true;
562 }
563 }
564 fPaint = paint;
565
566 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000567 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000568 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000569 }
570
571 // call this after any possible paint modifiers
572 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700573 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000574 return false;
575 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000576 return true;
577}
578
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579////////// macros to place around the internal draw calls //////////////////
580
reed3aafe112016-08-18 12:45:34 -0700581#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
582 this->predrawNotify(); \
583 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
584 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800585 SkDrawIter iter(this);
586
587
reed@google.com8926b162012-03-23 15:36:36 +0000588#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000589 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700590 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000591 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000592 SkDrawIter iter(this);
593
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000594#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000595 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700596 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000597 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000598 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000599
reedc83a2972015-07-16 07:40:45 -0700600#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
601 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700602 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700603 while (looper.next(type)) { \
604 SkDrawIter iter(this);
605
reed@google.com4e2b3d32011-04-07 14:18:59 +0000606#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000607
608////////////////////////////////////////////////////////////////////////////
609
msarettfbfa2582016-08-12 08:29:08 -0700610static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
611 if (bounds.isEmpty()) {
612 return SkRect::MakeEmpty();
613 }
614
615 // Expand bounds out by 1 in case we are anti-aliasing. We store the
616 // bounds as floats to enable a faster quick reject implementation.
617 SkRect dst;
618 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
619 return dst;
620}
621
mtkleinfeaadee2015-04-08 11:25:48 -0700622void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
623 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700624 fMCRec->reset(bounds);
625
626 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500627 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400628 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700629 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700630 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700631}
632
reedd9544982014-09-09 18:46:22 -0700633SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800634 if (device && device->forceConservativeRasterClip()) {
635 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
636 }
reed42b73eb2015-11-20 13:42:42 -0800637
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000638 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800639 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700640 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700641#ifdef SK_EXPERIMENTAL_SHADOWING
642 fLights = nullptr;
643#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644
645 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500646 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500647 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700648 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649
reeda499f902015-05-01 09:34:31 -0700650 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
651 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita713b8ef2017-04-28 10:57:24 -0400652 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700653
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655
halcanary96fcdcc2015-08-27 07:41:13 -0700656 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000657
reedf92c8662014-08-18 08:02:43 -0700658 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700659 // The root device and the canvas should always have the same pixel geometry
660 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800661 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700662 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500663
Mike Reedc42a1cd2017-02-14 14:25:14 -0500664 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700665 }
msarettfbfa2582016-08-12 08:29:08 -0700666
reedf92c8662014-08-18 08:02:43 -0700667 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668}
669
reed@google.comcde92112011-07-06 20:00:52 +0000670SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000671 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700672 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000673{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000674 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000675
halcanary96fcdcc2015-08-27 07:41:13 -0700676 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000677}
678
reed96a857e2015-01-25 10:33:58 -0800679SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000680 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800681 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000682{
683 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700684
Mike Reed566e53c2017-03-10 10:49:45 -0500685 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700686 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700687}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000688
reed78e27682014-11-19 08:04:34 -0800689SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700690 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700691 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700692{
693 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700694
Mike Reed566e53c2017-03-10 10:49:45 -0500695 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
696 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700697}
698
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000699SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000700 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700701 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000702{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700704
reedd9544982014-09-09 18:46:22 -0700705 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706}
707
robertphillipsfcf78292015-06-19 11:49:52 -0700708SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
709 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700710 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700711{
712 inc_canvas();
713
714 this->init(device, flags);
715}
716
reed4a8126e2014-09-22 07:29:03 -0700717SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700718 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700719 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700720{
721 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700722
Hal Canary704cd322016-11-07 14:13:52 -0500723 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
724 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700725}
reed29c857d2014-09-21 10:25:07 -0700726
Mike Reed356f7c22017-01-10 11:58:39 -0500727SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
728 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700729 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
730 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500731 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700732{
733 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700734
Mike Reed356f7c22017-01-10 11:58:39 -0500735 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500736 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000737}
738
Mike Reed356f7c22017-01-10 11:58:39 -0500739SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
740
Matt Sarett31f99ce2017-04-11 08:46:01 -0400741#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
742SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
743 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
744 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
745 , fAllocator(nullptr)
746{
747 inc_canvas();
748
749 SkBitmap tmp(bitmap);
750 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
751 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
752 this->init(device.get(), kDefault_InitFlags);
753}
754#endif
755
reed@android.com8a1c16f2008-12-17 15:59:43 +0000756SkCanvas::~SkCanvas() {
757 // free up the contents of our deque
758 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000759
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760 this->internalRestore(); // restore the last, since we're going away
761
halcanary385fe4d2015-08-26 13:07:48 -0700762 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000763
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764 dec_canvas();
765}
766
fmalita53d9f1c2016-01-25 06:23:54 -0800767#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768SkDrawFilter* SkCanvas::getDrawFilter() const {
769 return fMCRec->fFilter;
770}
771
772SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700773 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000774 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
775 return filter;
776}
fmalita77650002016-01-21 18:47:11 -0800777#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000778
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000779SkMetaData& SkCanvas::getMetaData() {
780 // metadata users are rare, so we lazily allocate it. If that changes we
781 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700782 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000783 fMetaData = new SkMetaData;
784 }
785 return *fMetaData;
786}
787
reed@android.com8a1c16f2008-12-17 15:59:43 +0000788///////////////////////////////////////////////////////////////////////////////
789
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000790void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700791 this->onFlush();
792}
793
794void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000795 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000796 if (device) {
797 device->flush();
798 }
799}
800
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000801SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000802 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000803 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
804}
805
senorblancoafc7cce2016-02-02 18:44:15 -0800806SkIRect SkCanvas::getTopLayerBounds() const {
807 SkBaseDevice* d = this->getTopDevice();
808 if (!d) {
809 return SkIRect::MakeEmpty();
810 }
811 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
812}
813
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000814SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000815 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000816 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400818 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819}
820
Florin Malita0ed3b642017-01-13 16:56:38 +0000821SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400822 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000823}
824
reed96472de2014-12-10 09:53:42 -0800825bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000826 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000827 if (!device) {
828 return false;
829 }
mtkleinf0f14112014-12-12 08:46:25 -0800830
Matt Sarett03dd6d52017-01-23 12:15:09 -0500831 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000832}
833
Mike Reed12e946b2017-04-17 10:53:29 -0400834bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
835 return pm.addr() && this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y);
836}
837
838bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
839 SkPixmap pm;
840 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
841}
842
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000843bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400844 SkPixmap pm;
845 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700846 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000847 }
848 return false;
849}
850
Matt Sarett03dd6d52017-01-23 12:15:09 -0500851bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000852 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000853 SkBaseDevice* device = this->getDevice();
854 if (!device) {
855 return false;
856 }
857
Matt Sarett03dd6d52017-01-23 12:15:09 -0500858 // This check gives us an early out and prevents generation ID churn on the surface.
859 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
860 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
861 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
862 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000863 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000864
Matt Sarett03dd6d52017-01-23 12:15:09 -0500865 // Tell our owning surface to bump its generation ID.
866 const bool completeOverwrite =
867 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700868 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700869
Matt Sarett03dd6d52017-01-23 12:15:09 -0500870 // This can still fail, most notably in the case of a invalid color type or alpha type
871 // conversion. We could pull those checks into this function and avoid the unnecessary
872 // generation ID bump. But then we would be performing those checks twice, since they
873 // are also necessary at the bitmap/pixmap entry points.
874 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000875}
reed@google.com51df9e32010-12-23 19:29:18 +0000876
reed@android.com8a1c16f2008-12-17 15:59:43 +0000877//////////////////////////////////////////////////////////////////////////////
878
reed2ff1fce2014-12-11 07:07:37 -0800879void SkCanvas::checkForDeferredSave() {
880 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800881 this->doSave();
882 }
883}
884
reedf0090cb2014-11-26 08:55:51 -0800885int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800886#ifdef SK_DEBUG
887 int count = 0;
888 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
889 for (;;) {
890 const MCRec* rec = (const MCRec*)iter.next();
891 if (!rec) {
892 break;
893 }
894 count += 1 + rec->fDeferredSaveCount;
895 }
896 SkASSERT(count == fSaveCount);
897#endif
898 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800899}
900
901int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800902 fSaveCount += 1;
903 fMCRec->fDeferredSaveCount += 1;
904 return this->getSaveCount() - 1; // return our prev value
905}
906
907void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800908 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700909
910 SkASSERT(fMCRec->fDeferredSaveCount > 0);
911 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800912 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800913}
914
915void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800916 if (fMCRec->fDeferredSaveCount > 0) {
917 SkASSERT(fSaveCount > 1);
918 fSaveCount -= 1;
919 fMCRec->fDeferredSaveCount -= 1;
920 } else {
921 // check for underflow
922 if (fMCStack.count() > 1) {
923 this->willRestore();
924 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700925 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800926 this->internalRestore();
927 this->didRestore();
928 }
reedf0090cb2014-11-26 08:55:51 -0800929 }
930}
931
932void SkCanvas::restoreToCount(int count) {
933 // sanity check
934 if (count < 1) {
935 count = 1;
936 }
mtkleinf0f14112014-12-12 08:46:25 -0800937
reedf0090cb2014-11-26 08:55:51 -0800938 int n = this->getSaveCount() - count;
939 for (int i = 0; i < n; ++i) {
940 this->restore();
941 }
942}
943
reed2ff1fce2014-12-11 07:07:37 -0800944void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700946 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000947 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000948
Mike Reedc42a1cd2017-02-14 14:25:14 -0500949 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950}
951
reed4960eee2015-12-18 07:09:18 -0800952bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800953 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954}
955
reed4960eee2015-12-18 07:09:18 -0800956bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700957 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500958 SkIRect clipBounds = this->getDeviceClipBounds();
959 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000960 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000961 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000962
reed96e657d2015-03-10 17:30:07 -0700963 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
964
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000965 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700966 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800967 if (bounds && !imageFilter->canComputeFastBounds()) {
968 bounds = nullptr;
969 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000970 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000971 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700972 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000974
reed96e657d2015-03-10 17:30:07 -0700975 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976 r.roundOut(&ir);
977 // early exit if the layer's bounds are clipped out
978 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800979 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500980 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700981 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700982 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000983 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000984 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000985 }
986 } else { // no user bounds, so just use the clip
987 ir = clipBounds;
988 }
reed180aec42015-03-11 10:39:04 -0700989 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000990
reed4960eee2015-12-18 07:09:18 -0800991 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700992 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700993 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700994 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000995 }
996
997 if (intersection) {
998 *intersection = ir;
999 }
1000 return true;
1001}
1002
reed4960eee2015-12-18 07:09:18 -08001003
reed4960eee2015-12-18 07:09:18 -08001004int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1005 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001006}
1007
reed70ee31b2015-12-10 13:44:45 -08001008int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001009 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1010}
1011
1012int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1013 SaveLayerRec rec(origRec);
1014 if (gIgnoreSaveLayerBounds) {
1015 rec.fBounds = nullptr;
1016 }
1017 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1018 fSaveCount += 1;
1019 this->internalSaveLayer(rec, strategy);
1020 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001021}
1022
reeda2217ef2016-07-20 06:04:34 -07001023void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001024 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001025 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001026 SkDraw draw;
1027 SkRasterClip rc;
1028 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1029 if (!dst->accessPixels(&draw.fDst)) {
1030 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001031 }
reeda2217ef2016-07-20 06:04:34 -07001032 draw.fMatrix = &SkMatrix::I();
1033 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001034
1035 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001036 if (filter) {
1037 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1038 }
reeda2217ef2016-07-20 06:04:34 -07001039
Mike Reedc42a1cd2017-02-14 14:25:14 -05001040 int x = src->getOrigin().x() - dstOrigin.x();
1041 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001042 auto special = src->snapSpecial();
1043 if (special) {
Mike Reeda1361362017-03-07 09:37:29 -05001044 dst->drawSpecial(special.get(), x, y, p);
reeda2217ef2016-07-20 06:04:34 -07001045 }
robertphillips7354a4b2015-12-16 05:08:27 -08001046}
reed70ee31b2015-12-10 13:44:45 -08001047
reed129ed1c2016-02-22 06:42:31 -08001048static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1049 const SkPaint* paint) {
1050 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1051 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001052 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001053 const bool hasImageFilter = paint && paint->getImageFilter();
1054
1055 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1056 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1057 // force to L32
1058 return SkImageInfo::MakeN32(w, h, alphaType);
1059 } else {
1060 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001061 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001062 }
1063}
1064
reed4960eee2015-12-18 07:09:18 -08001065void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1066 const SkRect* bounds = rec.fBounds;
1067 const SkPaint* paint = rec.fPaint;
1068 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1069
reed8c30a812016-04-20 16:36:51 -07001070 SkLazyPaint lazyP;
1071 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1072 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001073 SkMatrix remainder;
1074 SkSize scale;
1075 /*
1076 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1077 * but they do handle scaling. To accommodate this, we do the following:
1078 *
1079 * 1. Stash off the current CTM
1080 * 2. Decompose the CTM into SCALE and REMAINDER
1081 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1082 * contains the REMAINDER
1083 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1084 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1085 * of the original imagefilter, and draw that (via drawSprite)
1086 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1087 *
1088 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1089 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1090 */
reed96a04f32016-04-25 09:25:15 -07001091 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001092 stashedMatrix.decomposeScale(&scale, &remainder))
1093 {
1094 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1095 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1096 SkPaint* p = lazyP.set(*paint);
1097 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1098 SkFilterQuality::kLow_SkFilterQuality,
1099 sk_ref_sp(imageFilter)));
1100 imageFilter = p->getImageFilter();
1101 paint = p;
1102 }
reed8c30a812016-04-20 16:36:51 -07001103
junov@chromium.orga907ac32012-02-24 21:54:07 +00001104 // do this before we create the layer. We don't call the public save() since
1105 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001106 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001107
junov@chromium.orga907ac32012-02-24 21:54:07 +00001108 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001109 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001110 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111 }
1112
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001113 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1114 // the clipRectBounds() call above?
1115 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001116 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001117 }
1118
reed4960eee2015-12-18 07:09:18 -08001119 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001120 SkPixelGeometry geo = fProps.pixelGeometry();
1121 if (paint) {
reed76033be2015-03-14 10:54:31 -07001122 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001123 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001124 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001125 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001126 }
1127 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001128
robertphillips5139e502016-07-19 05:10:40 -07001129 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001130 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001131 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001132 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001133 }
reedb2db8982014-11-13 12:41:02 -08001134
robertphillips5139e502016-07-19 05:10:40 -07001135 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001136 paint);
1137
Hal Canary704cd322016-11-07 14:13:52 -05001138 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001139 {
reed70ee31b2015-12-10 13:44:45 -08001140 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001141 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001142 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001143 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001144 preserveLCDText,
1145 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001146 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1147 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001148 return;
reed61f501f2015-04-29 08:34:00 -07001149 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001150 }
Florin Malita713b8ef2017-04-28 10:57:24 -04001151 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001152
Mike Reedb43a3e02017-02-11 10:18:58 -05001153 // only have a "next" if this new layer doesn't affect the clip (rare)
1154 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001155 fMCRec->fLayer = layer;
1156 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001157
Mike Reedc61abee2017-02-28 17:45:27 -05001158 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001159 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001160 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001161 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001162
Mike Reedc42a1cd2017-02-14 14:25:14 -05001163 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1164
1165 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1166 if (layer->fNext) {
1167 // need to punch a hole in the previous device, so we don't draw there, given that
1168 // the new top-layer will allow drawing to happen "below" it.
1169 SkRegion hole(ir);
1170 do {
1171 layer = layer->fNext;
1172 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1173 } while (layer->fNext);
1174 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001175}
1176
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001177int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001178 if (0xFF == alpha) {
1179 return this->saveLayer(bounds, nullptr);
1180 } else {
1181 SkPaint tmpPaint;
1182 tmpPaint.setAlpha(alpha);
1183 return this->saveLayer(bounds, &tmpPaint);
1184 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001185}
1186
reed@android.com8a1c16f2008-12-17 15:59:43 +00001187void SkCanvas::internalRestore() {
1188 SkASSERT(fMCStack.count() != 0);
1189
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001190 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001191 DeviceCM* layer = fMCRec->fLayer; // may be null
1192 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001193 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194
1195 // now do the normal restore()
1196 fMCRec->~MCRec(); // balanced in save()
1197 fMCStack.pop_back();
1198 fMCRec = (MCRec*)fMCStack.back();
1199
Mike Reedc42a1cd2017-02-14 14:25:14 -05001200 if (fMCRec) {
1201 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1202 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001203
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1205 since if we're being recorded, we don't want to record this (the
1206 recorder will have already recorded the restore).
1207 */
bsalomon49f085d2014-09-05 13:34:00 -07001208 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001209 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001210 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001211 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
1212 layer->fPaint.get());
reed8c30a812016-04-20 16:36:51 -07001213 // restore what we smashed in internalSaveLayer
1214 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001215 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001216 delete layer;
reedb679ca82015-04-07 04:40:48 -07001217 } else {
1218 // we're at the root
reeda499f902015-05-01 09:34:31 -07001219 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001220 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001221 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001223 }
msarettfbfa2582016-08-12 08:29:08 -07001224
1225 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001226 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001227 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1228 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001229}
1230
reede8f30622016-03-23 18:59:25 -07001231sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001232 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001233 props = &fProps;
1234 }
1235 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001236}
1237
reede8f30622016-03-23 18:59:25 -07001238sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001239 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001240 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001241}
1242
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001243SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001244 return this->onImageInfo();
1245}
1246
1247SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001248 SkBaseDevice* dev = this->getDevice();
1249 if (dev) {
1250 return dev->imageInfo();
1251 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001252 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001253 }
1254}
1255
brianosman898235c2016-04-06 07:38:23 -07001256bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001257 return this->onGetProps(props);
1258}
1259
1260bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001261 SkBaseDevice* dev = this->getDevice();
1262 if (dev) {
1263 if (props) {
1264 *props = fProps;
1265 }
1266 return true;
1267 } else {
1268 return false;
1269 }
1270}
1271
reed6ceeebd2016-03-09 14:26:26 -08001272bool SkCanvas::peekPixels(SkPixmap* pmap) {
1273 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001274}
1275
reed884e97c2015-05-26 11:31:54 -07001276bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001277 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001278 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001279}
1280
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001281void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001282 SkPixmap pmap;
1283 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001284 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001285 }
1286 if (info) {
1287 *info = pmap.info();
1288 }
1289 if (rowBytes) {
1290 *rowBytes = pmap.rowBytes();
1291 }
1292 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001293 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001294 }
reed884e97c2015-05-26 11:31:54 -07001295 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001296}
1297
reed884e97c2015-05-26 11:31:54 -07001298bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001299 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001300 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001301}
1302
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001304
reed7503d602016-07-15 14:23:29 -07001305void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001307 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308 paint = &tmp;
1309 }
reed@google.com4b226022011-01-11 18:32:13 +00001310
reed@google.com8926b162012-03-23 15:36:36 +00001311 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001312
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001314 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001315 paint = &looper.paint();
1316 SkImageFilter* filter = paint->getImageFilter();
1317 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001318 if (filter) {
1319 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1320 if (specialImage) {
Mike Reeda1361362017-03-07 09:37:29 -05001321 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint);
Robert Phillips833dcf42016-11-18 08:44:13 -05001322 }
reed@google.com76dd2772012-01-05 21:15:07 +00001323 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001324 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001325 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326 }
reeda2217ef2016-07-20 06:04:34 -07001327
reed@google.com4e2b3d32011-04-07 14:18:59 +00001328 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001329}
1330
reed32704672015-12-16 08:27:10 -08001331/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001332
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001333void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001334 if (dx || dy) {
1335 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001336 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001337
reedfe69b502016-09-12 06:31:48 -07001338 // Translate shouldn't affect the is-scale-translateness of the matrix.
1339 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001340
Mike Reedc42a1cd2017-02-14 14:25:14 -05001341 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001342
reedfe69b502016-09-12 06:31:48 -07001343 this->didTranslate(dx,dy);
1344 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001345}
1346
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001347void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001348 SkMatrix m;
1349 m.setScale(sx, sy);
1350 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001351}
1352
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001353void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001354 SkMatrix m;
1355 m.setRotate(degrees);
1356 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001357}
1358
bungeman7438bfc2016-07-12 15:01:19 -07001359void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1360 SkMatrix m;
1361 m.setRotate(degrees, px, py);
1362 this->concat(m);
1363}
1364
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001365void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001366 SkMatrix m;
1367 m.setSkew(sx, sy);
1368 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001369}
1370
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001371void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001372 if (matrix.isIdentity()) {
1373 return;
1374 }
1375
reed2ff1fce2014-12-11 07:07:37 -08001376 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001377 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001378 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001379
Mike Reed7627fa52017-02-08 10:07:53 -05001380 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001381
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001382 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001383}
1384
reed8c30a812016-04-20 16:36:51 -07001385void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001386 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001387 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001388
Mike Reedc42a1cd2017-02-14 14:25:14 -05001389 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001390}
1391
1392void SkCanvas::setMatrix(const SkMatrix& matrix) {
1393 this->checkForDeferredSave();
1394 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001395 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001396}
1397
reed@android.com8a1c16f2008-12-17 15:59:43 +00001398void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001399 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001400}
1401
vjiaoblack95302da2016-07-21 10:25:54 -07001402#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001403void SkCanvas::translateZ(SkScalar z) {
1404 this->checkForDeferredSave();
1405 this->fMCRec->fCurDrawDepth += z;
1406 this->didTranslateZ(z);
1407}
1408
1409SkScalar SkCanvas::getZ() const {
1410 return this->fMCRec->fCurDrawDepth;
1411}
1412
vjiaoblack95302da2016-07-21 10:25:54 -07001413void SkCanvas::setLights(sk_sp<SkLights> lights) {
1414 this->fLights = lights;
1415}
1416
1417sk_sp<SkLights> SkCanvas::getLights() const {
1418 return this->fLights;
1419}
1420#endif
1421
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422//////////////////////////////////////////////////////////////////////////////
1423
Mike Reedc1f77742016-12-09 09:00:50 -05001424void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001425 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001426 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1427 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001428}
1429
Mike Reedc1f77742016-12-09 09:00:50 -05001430void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001431 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001432
Mike Reed7627fa52017-02-08 10:07:53 -05001433 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001434
reedc64eff52015-11-21 12:39:45 -08001435 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001436 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1437 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001438 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439}
1440
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001441void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1442 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001443 if (fClipRestrictionRect.isEmpty()) {
1444 // we notify the device, but we *dont* resolve deferred saves (since we're just
1445 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001446 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001447 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001448 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001449 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001450 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001451 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001452 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1453 }
1454}
1455
Mike Reedc1f77742016-12-09 09:00:50 -05001456void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001457 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001458 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001459 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001460 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1461 } else {
1462 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001463 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001464}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001465
Mike Reedc1f77742016-12-09 09:00:50 -05001466void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001467 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001468
Brian Salomona3b45d42016-10-03 11:36:16 -04001469 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001470
Mike Reed7627fa52017-02-08 10:07:53 -05001471 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001472
Brian Salomona3b45d42016-10-03 11:36:16 -04001473 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1474 isAA);
1475 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001476}
1477
Mike Reedc1f77742016-12-09 09:00:50 -05001478void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001479 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001480 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001481
1482 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1483 SkRect r;
1484 if (path.isRect(&r)) {
1485 this->onClipRect(r, op, edgeStyle);
1486 return;
1487 }
1488 SkRRect rrect;
1489 if (path.isOval(&r)) {
1490 rrect.setOval(r);
1491 this->onClipRRect(rrect, op, edgeStyle);
1492 return;
1493 }
1494 if (path.isRRect(&rrect)) {
1495 this->onClipRRect(rrect, op, edgeStyle);
1496 return;
1497 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001498 }
robertphillips39f05382015-11-24 09:30:12 -08001499
1500 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001501}
1502
Mike Reedc1f77742016-12-09 09:00:50 -05001503void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001504 AutoValidateClip avc(this);
1505
Brian Salomona3b45d42016-10-03 11:36:16 -04001506 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001507
Mike Reed7627fa52017-02-08 10:07:53 -05001508 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001509
Brian Salomona3b45d42016-10-03 11:36:16 -04001510 const SkPath* rasterClipPath = &path;
1511 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001512 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1513 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001514 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001515}
1516
Mike Reedc1f77742016-12-09 09:00:50 -05001517void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001518 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001519 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001520}
1521
Mike Reedc1f77742016-12-09 09:00:50 -05001522void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001523 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001524
reed@google.com5c3d1472011-02-22 19:12:23 +00001525 AutoValidateClip avc(this);
1526
reed73603f32016-09-20 08:42:38 -07001527 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001528 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001529}
1530
reed@google.com819c9212011-02-23 18:56:55 +00001531#ifdef SK_DEBUG
1532void SkCanvas::validateClip() const {
1533 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001534 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001535 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001536 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001537 return;
1538 }
reed@google.com819c9212011-02-23 18:56:55 +00001539}
1540#endif
1541
Mike Reeda1361362017-03-07 09:37:29 -05001542bool SkCanvas::androidFramework_isClipAA() const {
1543 bool containsAA = false;
1544
1545 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1546
1547 return containsAA;
1548}
1549
1550class RgnAccumulator {
1551 SkRegion* fRgn;
1552public:
1553 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1554 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1555 SkIPoint origin = device->getOrigin();
1556 if (origin.x() | origin.y()) {
1557 rgn->translate(origin.x(), origin.y());
1558 }
1559 fRgn->op(*rgn, SkRegion::kUnion_Op);
1560 }
1561};
1562
1563void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1564 RgnAccumulator accum(rgn);
1565 SkRegion tmp;
1566
1567 rgn->setEmpty();
1568 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001569}
1570
reed@google.com5c3d1472011-02-22 19:12:23 +00001571///////////////////////////////////////////////////////////////////////////////
1572
reed@google.com754de5f2014-02-24 19:38:20 +00001573bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001574 return fMCRec->fRasterClip.isEmpty();
1575
1576 // TODO: should we only use the conservative answer in a recording canvas?
1577#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001578 SkBaseDevice* dev = this->getTopDevice();
1579 // if no device we return true
1580 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001581#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001582}
1583
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001584bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001585 SkBaseDevice* dev = this->getTopDevice();
1586 // if no device we return false
1587 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001588}
1589
msarettfbfa2582016-08-12 08:29:08 -07001590static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1591#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1592 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1593 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1594 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1595 return 0xF != _mm_movemask_ps(mask);
1596#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1597 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1598 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1599 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1600 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1601#else
1602 SkRect devRectAsRect;
1603 SkRect devClipAsRect;
1604 devRect.store(&devRectAsRect.fLeft);
1605 devClip.store(&devClipAsRect.fLeft);
1606 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1607#endif
1608}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001609
msarettfbfa2582016-08-12 08:29:08 -07001610// It's important for this function to not be inlined. Otherwise the compiler will share code
1611// between the fast path and the slow path, resulting in two slow paths.
1612static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1613 const SkMatrix& matrix) {
1614 SkRect deviceRect;
1615 matrix.mapRect(&deviceRect, src);
1616 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1617}
1618
1619bool SkCanvas::quickReject(const SkRect& src) const {
1620#ifdef SK_DEBUG
1621 // Verify that fDeviceClipBounds are set properly.
1622 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001623 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001624 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001625 } else {
msarettfbfa2582016-08-12 08:29:08 -07001626 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001627 }
msarettfbfa2582016-08-12 08:29:08 -07001628
msarett9637ea92016-08-18 14:03:30 -07001629 // Verify that fIsScaleTranslate is set properly.
1630 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001631#endif
1632
msarett9637ea92016-08-18 14:03:30 -07001633 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001634 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1635 }
1636
1637 // We inline the implementation of mapScaleTranslate() for the fast path.
1638 float sx = fMCRec->fMatrix.getScaleX();
1639 float sy = fMCRec->fMatrix.getScaleY();
1640 float tx = fMCRec->fMatrix.getTranslateX();
1641 float ty = fMCRec->fMatrix.getTranslateY();
1642 Sk4f scale(sx, sy, sx, sy);
1643 Sk4f trans(tx, ty, tx, ty);
1644
1645 // Apply matrix.
1646 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1647
1648 // Make sure left < right, top < bottom.
1649 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1650 Sk4f min = Sk4f::Min(ltrb, rblt);
1651 Sk4f max = Sk4f::Max(ltrb, rblt);
1652 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1653 // ARM this sequence generates the fastest (a single instruction).
1654 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1655
1656 // Check if the device rect is NaN or outside the clip.
1657 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658}
1659
reed@google.com3b3e8952012-08-16 20:53:31 +00001660bool SkCanvas::quickReject(const SkPath& path) const {
1661 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662}
1663
Mike Reed42e8c532017-01-23 14:09:13 -05001664SkRect SkCanvas::onGetLocalClipBounds() const {
1665 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001666 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001667 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668 }
1669
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001670 SkMatrix inverse;
1671 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001672 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001673 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001674 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001675
Mike Reed42e8c532017-01-23 14:09:13 -05001676 SkRect bounds;
1677 SkRect r;
1678 // adjust it outwards in case we are antialiasing
1679 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001680
Mike Reed42e8c532017-01-23 14:09:13 -05001681 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1682 ibounds.fRight + inset, ibounds.fBottom + inset);
1683 inverse.mapRect(&bounds, r);
1684 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001685}
1686
Mike Reed42e8c532017-01-23 14:09:13 -05001687SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001688 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001689}
1690
reed@android.com8a1c16f2008-12-17 15:59:43 +00001691const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001692 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001693}
1694
Brian Osman11052242016-10-27 14:47:55 -04001695GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001696 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001697 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001698}
1699
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001700GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001701 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001702 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001703}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001704
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001705void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1706 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001707 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001708 if (outer.isEmpty()) {
1709 return;
1710 }
1711 if (inner.isEmpty()) {
1712 this->drawRRect(outer, paint);
1713 return;
1714 }
1715
1716 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001717 // be able to return ...
1718 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001719 //
1720 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001721 if (!outer.getBounds().contains(inner.getBounds())) {
1722 return;
1723 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001724
1725 this->onDrawDRRect(outer, inner, paint);
1726}
1727
reed41af9662015-01-05 07:49:08 -08001728// These need to stop being virtual -- clients need to override the onDraw... versions
1729
1730void SkCanvas::drawPaint(const SkPaint& paint) {
1731 this->onDrawPaint(paint);
1732}
1733
1734void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1735 this->onDrawRect(r, paint);
1736}
1737
msarettdca352e2016-08-26 06:37:45 -07001738void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1739 if (region.isEmpty()) {
1740 return;
1741 }
1742
1743 if (region.isRect()) {
1744 return this->drawIRect(region.getBounds(), paint);
1745 }
1746
1747 this->onDrawRegion(region, paint);
1748}
1749
reed41af9662015-01-05 07:49:08 -08001750void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1751 this->onDrawOval(r, paint);
1752}
1753
1754void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1755 this->onDrawRRect(rrect, paint);
1756}
1757
1758void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1759 this->onDrawPoints(mode, count, pts, paint);
1760}
1761
Mike Reede88a1cb2017-03-17 09:50:46 -04001762void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1763 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001764 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001765 this->onDrawVerticesObject(vertices.get(), mode, paint);
1766}
1767
1768void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1769 RETURN_ON_NULL(vertices);
1770 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001771}
1772
1773void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1774 this->onDrawPath(path, paint);
1775}
1776
reeda85d4d02015-05-06 12:56:48 -07001777void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001778 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001779 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001780}
1781
reede47829b2015-08-06 10:02:53 -07001782void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1783 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001784 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001785 if (dst.isEmpty() || src.isEmpty()) {
1786 return;
1787 }
1788 this->onDrawImageRect(image, &src, dst, paint, constraint);
1789}
reed41af9662015-01-05 07:49:08 -08001790
reed84984ef2015-07-17 07:09:43 -07001791void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1792 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001793 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001794 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001795}
1796
reede47829b2015-08-06 10:02:53 -07001797void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1798 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001799 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001800 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1801 constraint);
1802}
reede47829b2015-08-06 10:02:53 -07001803
reed4c21dc52015-06-25 12:32:03 -07001804void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1805 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001806 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001807 if (dst.isEmpty()) {
1808 return;
1809 }
msarett552bca92016-08-03 06:53:26 -07001810 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1811 this->onDrawImageNine(image, center, dst, paint);
1812 } else {
reede47829b2015-08-06 10:02:53 -07001813 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001814 }
reed4c21dc52015-06-25 12:32:03 -07001815}
1816
msarett16882062016-08-16 09:31:08 -07001817void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1818 const SkPaint* paint) {
1819 RETURN_ON_NULL(image);
1820 if (dst.isEmpty()) {
1821 return;
1822 }
msarett71df2d72016-09-30 12:41:42 -07001823
1824 SkIRect bounds;
1825 Lattice latticePlusBounds = lattice;
1826 if (!latticePlusBounds.fBounds) {
1827 bounds = SkIRect::MakeWH(image->width(), image->height());
1828 latticePlusBounds.fBounds = &bounds;
1829 }
1830
1831 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1832 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001833 } else {
1834 this->drawImageRect(image, dst, paint);
1835 }
1836}
1837
reed41af9662015-01-05 07:49:08 -08001838void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001839 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001840 return;
1841 }
reed41af9662015-01-05 07:49:08 -08001842 this->onDrawBitmap(bitmap, dx, dy, paint);
1843}
1844
reede47829b2015-08-06 10:02:53 -07001845void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001846 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001847 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001848 return;
1849 }
reede47829b2015-08-06 10:02:53 -07001850 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001851}
1852
reed84984ef2015-07-17 07:09:43 -07001853void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1854 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001855 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001856}
1857
reede47829b2015-08-06 10:02:53 -07001858void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1859 SrcRectConstraint constraint) {
1860 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1861 constraint);
1862}
reede47829b2015-08-06 10:02:53 -07001863
reed41af9662015-01-05 07:49:08 -08001864void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1865 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001866 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001867 return;
1868 }
msarett552bca92016-08-03 06:53:26 -07001869 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1870 this->onDrawBitmapNine(bitmap, center, dst, paint);
1871 } else {
reeda5517e22015-07-14 10:54:12 -07001872 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001873 }
reed41af9662015-01-05 07:49:08 -08001874}
1875
msarettc573a402016-08-02 08:05:56 -07001876void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1877 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001878 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001879 return;
1880 }
msarett71df2d72016-09-30 12:41:42 -07001881
1882 SkIRect bounds;
1883 Lattice latticePlusBounds = lattice;
1884 if (!latticePlusBounds.fBounds) {
1885 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1886 latticePlusBounds.fBounds = &bounds;
1887 }
1888
1889 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1890 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001891 } else {
msarett16882062016-08-16 09:31:08 -07001892 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001893 }
msarettc573a402016-08-02 08:05:56 -07001894}
1895
reed71c3c762015-06-24 10:29:17 -07001896void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001897 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001898 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001899 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001900 if (count <= 0) {
1901 return;
1902 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001903 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001904 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001905 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001906}
1907
reedf70b5312016-03-04 16:36:20 -08001908void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1909 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
tomhudsoncb3bd182016-05-18 07:24:16 -07001933void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1934 SkIRect layer_bounds = this->getTopLayerBounds();
1935 if (matrix) {
1936 *matrix = this->getTotalMatrix();
1937 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1938 }
1939 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001940 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001941 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1942 }
1943}
1944
reed@android.com8a1c16f2008-12-17 15:59:43 +00001945//////////////////////////////////////////////////////////////////////////////
1946// These are the virtual drawing methods
1947//////////////////////////////////////////////////////////////////////////////
1948
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001949void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001950 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001951 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1952 }
1953}
1954
reed41af9662015-01-05 07:49:08 -08001955void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001956 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001957 this->internalDrawPaint(paint);
1958}
1959
1960void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001961 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001962
1963 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001964 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001965 }
1966
reed@google.com4e2b3d32011-04-07 14:18:59 +00001967 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001968}
1969
reed41af9662015-01-05 07:49:08 -08001970void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1971 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001972 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001973 if ((long)count <= 0) {
1974 return;
1975 }
1976
Mike Reed822128b2017-02-28 16:41:03 -05001977 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001978 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001979 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001980 // special-case 2 points (common for drawing a single line)
1981 if (2 == count) {
1982 r.set(pts[0], pts[1]);
1983 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001984 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001985 }
Mike Reed822128b2017-02-28 16:41:03 -05001986 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001987 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1988 return;
1989 }
1990 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001991 }
reed@google.coma584aed2012-05-16 14:06:02 +00001992
halcanary96fcdcc2015-08-27 07:41:13 -07001993 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001994
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001995 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001996
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001998 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999 }
reed@google.com4b226022011-01-11 18:32:13 +00002000
reed@google.com4e2b3d32011-04-07 14:18:59 +00002001 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002002}
2003
reed4a167172016-08-18 17:15:25 -07002004static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2005 return ((intptr_t)paint.getImageFilter() |
2006#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2007 (intptr_t)canvas->getDrawFilter() |
2008#endif
2009 (intptr_t)paint.getLooper() ) != 0;
2010}
2011
reed41af9662015-01-05 07:49:08 -08002012void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002013 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002014 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002015 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2016 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2017 SkRect tmp(r);
2018 tmp.sort();
2019
Mike Reed822128b2017-02-28 16:41:03 -05002020 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002021 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2022 return;
2023 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002024 }
reed@google.com4b226022011-01-11 18:32:13 +00002025
reed4a167172016-08-18 17:15:25 -07002026 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002027 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002028
reed4a167172016-08-18 17:15:25 -07002029 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002030 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002031 }
2032
2033 LOOPER_END
2034 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002035 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002036 SkDrawIter iter(this);
2037 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002038 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002039 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002040 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002041}
2042
msarett44df6512016-08-25 13:54:30 -07002043void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002044 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002045 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002046 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002047 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2048 return;
2049 }
msarett44df6512016-08-25 13:54:30 -07002050 }
2051
Mike Reed822128b2017-02-28 16:41:03 -05002052 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002053
2054 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002055 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002056 }
2057
2058 LOOPER_END
2059}
2060
reed41af9662015-01-05 07:49:08 -08002061void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002062 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002063 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002064 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002065 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2066 return;
2067 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002068 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002069
Mike Reed822128b2017-02-28 16:41:03 -05002070 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002071
2072 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002073 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002074 }
2075
2076 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002077}
2078
bsalomonac3aa242016-08-19 11:25:19 -07002079void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2080 SkScalar sweepAngle, bool useCenter,
2081 const SkPaint& paint) {
2082 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002083 if (paint.canComputeFastBounds()) {
2084 SkRect storage;
2085 // Note we're using the entire oval as the bounds.
2086 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2087 return;
2088 }
bsalomonac3aa242016-08-19 11:25:19 -07002089 }
2090
Mike Reed822128b2017-02-28 16:41:03 -05002091 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002092
2093 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002094 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002095 }
2096
2097 LOOPER_END
2098}
2099
reed41af9662015-01-05 07:49:08 -08002100void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002101 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002102 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002103 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002104 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2105 return;
2106 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002107 }
2108
2109 if (rrect.isRect()) {
2110 // call the non-virtual version
2111 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002112 return;
2113 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002114 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002115 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2116 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002117 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002118
Mike Reed822128b2017-02-28 16:41:03 -05002119 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002120
2121 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002122 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002123 }
2124
2125 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002126}
2127
Mike Reed822128b2017-02-28 16:41:03 -05002128void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002129 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002130 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002131 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2132 return;
2133 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002134 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002135
Mike Reed822128b2017-02-28 16:41:03 -05002136 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002137
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002138 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002139 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002140 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002141
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002142 LOOPER_END
2143}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002144
reed41af9662015-01-05 07:49:08 -08002145void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002146 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002147 if (!path.isFinite()) {
2148 return;
2149 }
2150
Mike Reed822128b2017-02-28 16:41:03 -05002151 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002152 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002153 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002154 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2155 return;
2156 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002157 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002158
Mike Reed822128b2017-02-28 16:41:03 -05002159 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002160 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002161 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002162 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002163 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002164 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002165
Mike Reed822128b2017-02-28 16:41:03 -05002166 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002167
2168 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002169 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002170 }
2171
reed@google.com4e2b3d32011-04-07 14:18:59 +00002172 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002173}
2174
reed262a71b2015-12-05 13:07:27 -08002175bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002176 if (!paint.getImageFilter()) {
2177 return false;
2178 }
2179
2180 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002181 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002182 return false;
2183 }
2184
2185 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2186 // Once we can filter and the filter will return a result larger than itself, we should be
2187 // able to remove this constraint.
2188 // skbug.com/4526
2189 //
2190 SkPoint pt;
2191 ctm.mapXY(x, y, &pt);
2192 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2193 return ir.contains(fMCRec->fRasterClip.getBounds());
2194}
2195
reeda85d4d02015-05-06 12:56:48 -07002196void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002197 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002198 SkRect bounds = SkRect::MakeXYWH(x, y,
2199 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002200 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002201 SkRect tmp = bounds;
2202 if (paint) {
2203 paint->computeFastBounds(tmp, &tmp);
2204 }
2205 if (this->quickReject(tmp)) {
2206 return;
2207 }
reeda85d4d02015-05-06 12:56:48 -07002208 }
halcanary9d524f22016-03-29 09:03:52 -07002209
reeda85d4d02015-05-06 12:56:48 -07002210 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002211 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002212 paint = lazy.init();
2213 }
reed262a71b2015-12-05 13:07:27 -08002214
reeda2217ef2016-07-20 06:04:34 -07002215 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002216 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2217 *paint);
2218 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002219 special = this->getDevice()->makeSpecial(image);
2220 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002221 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002222 }
2223 }
2224
reed262a71b2015-12-05 13:07:27 -08002225 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2226
reeda85d4d02015-05-06 12:56:48 -07002227 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002228 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002229 if (special) {
2230 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002231 iter.fDevice->ctm().mapXY(x, y, &pt);
2232 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002233 SkScalarRoundToInt(pt.fX),
2234 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002235 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002236 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002237 }
reeda85d4d02015-05-06 12:56:48 -07002238 }
halcanary9d524f22016-03-29 09:03:52 -07002239
reeda85d4d02015-05-06 12:56:48 -07002240 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002241}
2242
reed41af9662015-01-05 07:49:08 -08002243void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002244 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002245 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002246 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002247 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002248 if (paint) {
2249 paint->computeFastBounds(dst, &storage);
2250 }
2251 if (this->quickReject(storage)) {
2252 return;
2253 }
reeda85d4d02015-05-06 12:56:48 -07002254 }
2255 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002256 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002257 paint = lazy.init();
2258 }
halcanary9d524f22016-03-29 09:03:52 -07002259
senorblancoc41e7e12015-12-07 12:51:30 -08002260 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002261 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002262
reeda85d4d02015-05-06 12:56:48 -07002263 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002264 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002265 }
halcanary9d524f22016-03-29 09:03:52 -07002266
reeda85d4d02015-05-06 12:56:48 -07002267 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002268}
2269
reed41af9662015-01-05 07:49:08 -08002270void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002271 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002272 SkDEBUGCODE(bitmap.validate();)
2273
reed33366972015-10-08 09:22:02 -07002274 if (bitmap.drawsNothing()) {
2275 return;
2276 }
2277
2278 SkLazyPaint lazy;
2279 if (nullptr == paint) {
2280 paint = lazy.init();
2281 }
2282
Mike Reed822128b2017-02-28 16:41:03 -05002283 SkRect bounds;
2284 bitmap.getBounds(&bounds);
2285 bounds.offset(x, y);
2286 bool canFastBounds = paint->canComputeFastBounds();
2287 if (canFastBounds) {
2288 SkRect storage;
2289 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002290 return;
2291 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002292 }
reed@google.com4b226022011-01-11 18:32:13 +00002293
reeda2217ef2016-07-20 06:04:34 -07002294 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002295 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2296 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002297 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002298 special = this->getDevice()->makeSpecial(bitmap);
2299 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002300 drawAsSprite = false;
2301 }
2302 }
2303
Mike Reed822128b2017-02-28 16:41:03 -05002304 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2305
2306 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002307
2308 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002309 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002310 if (special) {
reed262a71b2015-12-05 13:07:27 -08002311 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002312 iter.fDevice->ctm().mapXY(x, y, &pt);
2313 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002314 SkScalarRoundToInt(pt.fX),
2315 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002316 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002317 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002318 }
reed33366972015-10-08 09:22:02 -07002319 }
msarettfbfa2582016-08-12 08:29:08 -07002320
reed33366972015-10-08 09:22:02 -07002321 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002322}
2323
reed@google.com9987ec32011-09-07 11:57:52 +00002324// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002325void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002326 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002327 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002328 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002329 return;
2330 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002331
halcanary96fcdcc2015-08-27 07:41:13 -07002332 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002333 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002334 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2335 return;
2336 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002337 }
reed@google.com3d608122011-11-21 15:16:16 +00002338
reed@google.com33535f32012-09-25 15:37:50 +00002339 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002340 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002341 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002342 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002343
senorblancoc41e7e12015-12-07 12:51:30 -08002344 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002345 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002346
reed@google.com33535f32012-09-25 15:37:50 +00002347 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002348 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002349 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002350
reed@google.com33535f32012-09-25 15:37:50 +00002351 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352}
2353
reed41af9662015-01-05 07:49:08 -08002354void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002355 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002356 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002357 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002358 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002359}
2360
reed4c21dc52015-06-25 12:32:03 -07002361void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2362 const SkPaint* paint) {
2363 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002364
halcanary96fcdcc2015-08-27 07:41:13 -07002365 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002366 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002367 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2368 return;
2369 }
reed@google.com3d608122011-11-21 15:16:16 +00002370 }
halcanary9d524f22016-03-29 09:03:52 -07002371
reed4c21dc52015-06-25 12:32:03 -07002372 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002373 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002374 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002375 }
halcanary9d524f22016-03-29 09:03:52 -07002376
senorblancoc41e7e12015-12-07 12:51:30 -08002377 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002378
reed4c21dc52015-06-25 12:32:03 -07002379 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002380 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002381 }
halcanary9d524f22016-03-29 09:03:52 -07002382
reed4c21dc52015-06-25 12:32:03 -07002383 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002384}
2385
reed41af9662015-01-05 07:49:08 -08002386void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2387 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002388 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002389 SkDEBUGCODE(bitmap.validate();)
2390
halcanary96fcdcc2015-08-27 07:41:13 -07002391 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002392 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002393 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2394 return;
2395 }
reed4c21dc52015-06-25 12:32:03 -07002396 }
halcanary9d524f22016-03-29 09:03:52 -07002397
reed4c21dc52015-06-25 12:32:03 -07002398 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002399 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002400 paint = lazy.init();
2401 }
halcanary9d524f22016-03-29 09:03:52 -07002402
senorblancoc41e7e12015-12-07 12:51:30 -08002403 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002404
reed4c21dc52015-06-25 12:32:03 -07002405 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002406 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002407 }
halcanary9d524f22016-03-29 09:03:52 -07002408
reed4c21dc52015-06-25 12:32:03 -07002409 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002410}
2411
msarett16882062016-08-16 09:31:08 -07002412void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2413 const SkPaint* paint) {
2414 if (nullptr == paint || paint->canComputeFastBounds()) {
2415 SkRect storage;
2416 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2417 return;
2418 }
2419 }
2420
2421 SkLazyPaint lazy;
2422 if (nullptr == paint) {
2423 paint = lazy.init();
2424 }
2425
2426 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2427
2428 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002429 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002430 }
2431
2432 LOOPER_END
2433}
2434
2435void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2436 const SkRect& dst, const SkPaint* paint) {
2437 if (nullptr == paint || paint->canComputeFastBounds()) {
2438 SkRect storage;
2439 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2440 return;
2441 }
2442 }
2443
2444 SkLazyPaint lazy;
2445 if (nullptr == paint) {
2446 paint = lazy.init();
2447 }
2448
2449 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2450
2451 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002452 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002453 }
2454
2455 LOOPER_END
2456}
2457
reed@google.comf67e4cf2011-03-15 20:56:58 +00002458class SkDeviceFilteredPaint {
2459public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002460 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002461 uint32_t filteredFlags = device->filterTextFlags(paint);
2462 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002463 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002464 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002465 fPaint = newPaint;
2466 } else {
2467 fPaint = &paint;
2468 }
2469 }
2470
reed@google.comf67e4cf2011-03-15 20:56:58 +00002471 const SkPaint& paint() const { return *fPaint; }
2472
2473private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002474 const SkPaint* fPaint;
2475 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002476};
2477
reed@google.come0d9ce82014-04-23 04:00:17 +00002478void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2479 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002480 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481
2482 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002483 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002484 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002485 }
2486
reed@google.com4e2b3d32011-04-07 14:18:59 +00002487 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488}
2489
reed@google.come0d9ce82014-04-23 04:00:17 +00002490void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2491 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002492 SkPoint textOffset = SkPoint::Make(0, 0);
2493
halcanary96fcdcc2015-08-27 07:41:13 -07002494 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002495
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002497 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002498 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002499 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002500 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002501
reed@google.com4e2b3d32011-04-07 14:18:59 +00002502 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503}
2504
reed@google.come0d9ce82014-04-23 04:00:17 +00002505void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2506 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002507
2508 SkPoint textOffset = SkPoint::Make(0, constY);
2509
halcanary96fcdcc2015-08-27 07:41:13 -07002510 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002511
reed@android.com8a1c16f2008-12-17 15:59:43 +00002512 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002513 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002514 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002515 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002516 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002517
reed@google.com4e2b3d32011-04-07 14:18:59 +00002518 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002519}
2520
reed@google.come0d9ce82014-04-23 04:00:17 +00002521void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2522 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002523 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002524
reed@android.com8a1c16f2008-12-17 15:59:43 +00002525 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002526 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002527 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002528 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002529
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002530 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002531}
2532
reed45561a02016-07-07 12:47:17 -07002533void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2534 const SkRect* cullRect, const SkPaint& paint) {
2535 if (cullRect && this->quickReject(*cullRect)) {
2536 return;
2537 }
2538
2539 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2540
2541 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002542 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002543 }
2544
2545 LOOPER_END
2546}
2547
fmalita00d5c2c2014-08-21 08:53:26 -07002548void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2549 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002550
fmalita85d5eb92015-03-04 11:20:12 -08002551 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002552 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002553 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002554 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002555 SkRect tmp;
2556 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2557 return;
2558 }
2559 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002560 }
2561
fmalita024f9962015-03-03 19:08:17 -08002562 // We cannot filter in the looper as we normally do, because the paint is
2563 // incomplete at this point (text-related attributes are embedded within blob run paints).
2564 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002565 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002566
fmalita85d5eb92015-03-04 11:20:12 -08002567 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002568
fmalitaaa1b9122014-08-28 14:32:24 -07002569 while (iter.next()) {
2570 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002571 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002572 }
2573
fmalitaaa1b9122014-08-28 14:32:24 -07002574 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002575
2576 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002577}
2578
Cary Clark2a475ea2017-04-28 15:35:12 -04002579void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2580 this->drawText(string.c_str(), string.size(), x, y, paint);
2581}
2582
reed@google.come0d9ce82014-04-23 04:00:17 +00002583// These will become non-virtual, so they always call the (virtual) onDraw... method
2584void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2585 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002586 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002587 if (byteLength) {
2588 this->onDrawText(text, byteLength, x, y, paint);
2589 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002590}
2591void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2592 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002593 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002594 if (byteLength) {
2595 this->onDrawPosText(text, byteLength, pos, paint);
2596 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002597}
2598void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2599 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002600 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002601 if (byteLength) {
2602 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2603 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002604}
2605void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2606 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002607 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002608 if (byteLength) {
2609 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2610 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002611}
reed45561a02016-07-07 12:47:17 -07002612void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2613 const SkRect* cullRect, const SkPaint& paint) {
2614 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2615 if (byteLength) {
2616 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2617 }
2618}
fmalita00d5c2c2014-08-21 08:53:26 -07002619void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2620 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002621 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002622 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002623 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002624}
reed@google.come0d9ce82014-04-23 04:00:17 +00002625
Mike Reede88a1cb2017-03-17 09:50:46 -04002626void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2627 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002628 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2629 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2630
2631 while (iter.next()) {
2632 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002633 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002634 }
2635
2636 LOOPER_END
2637}
2638
dandovb3c9d1c2014-08-12 08:34:29 -07002639void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002640 const SkPoint texCoords[4], SkBlendMode bmode,
2641 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002642 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002643 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002644 return;
2645 }
mtklein6cfa73a2014-08-13 13:33:49 -07002646
Mike Reedfaba3712016-11-03 14:45:31 -04002647 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002648}
2649
2650void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002651 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002652 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002653 // Since a patch is always within the convex hull of the control points, we discard it when its
2654 // bounding rectangle is completely outside the current clip.
2655 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002656 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002657 if (this->quickReject(bounds)) {
2658 return;
2659 }
mtklein6cfa73a2014-08-13 13:33:49 -07002660
halcanary96fcdcc2015-08-27 07:41:13 -07002661 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002662
dandovecfff212014-08-04 10:02:00 -07002663 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002664 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002665 }
mtklein6cfa73a2014-08-13 13:33:49 -07002666
dandovecfff212014-08-04 10:02:00 -07002667 LOOPER_END
2668}
2669
reeda8db7282015-07-07 10:22:31 -07002670void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002671 RETURN_ON_NULL(dr);
2672 if (x || y) {
2673 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2674 this->onDrawDrawable(dr, &matrix);
2675 } else {
2676 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002677 }
2678}
2679
reeda8db7282015-07-07 10:22:31 -07002680void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
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) {
danakj9881d632014-11-26 12:41:06 -08002730 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002731 SkPaint paint;
2732
2733 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002734 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 this->drawPaint(paint);
2736}
2737
2738void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002739 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002740 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2742}
2743
Mike Reed3661bc92017-02-22 13:21:42 -05002744void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002745 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002746 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002747
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748 pts[0].set(x0, y0);
2749 pts[1].set(x1, y1);
2750 this->drawPoints(kLines_PointMode, 2, pts, paint);
2751}
2752
Mike Reed3661bc92017-02-22 13:21:42 -05002753void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002754 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002755 if (radius < 0) {
2756 radius = 0;
2757 }
2758
2759 SkRect r;
2760 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002761 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762}
2763
2764void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2765 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002766 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002768 SkRRect rrect;
2769 rrect.setRectXY(r, rx, ry);
2770 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002771 } else {
2772 this->drawRect(r, paint);
2773 }
2774}
2775
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2777 SkScalar sweepAngle, bool useCenter,
2778 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002779 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002780 if (oval.isEmpty() || !sweepAngle) {
2781 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782 }
bsalomon21af9ca2016-08-25 12:29:23 -07002783 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784}
2785
2786void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2787 const SkPath& path, SkScalar hOffset,
2788 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002789 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002791
reed@android.com8a1c16f2008-12-17 15:59:43 +00002792 matrix.setTranslate(hOffset, vOffset);
2793 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2794}
2795
reed@android.comf76bacf2009-05-13 14:00:33 +00002796///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002797
2798/**
2799 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2800 * against the playback cost of recursing into the subpicture to get at its actual ops.
2801 *
2802 * For now we pick a conservatively small value, though measurement (and other heuristics like
2803 * the type of ops contained) may justify changing this value.
2804 */
2805#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002806
reedd5fa1a42014-08-09 11:08:05 -07002807void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002808 RETURN_ON_NULL(picture);
2809
reed1c2c4412015-04-30 13:09:24 -07002810 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002811 if (matrix && matrix->isIdentity()) {
2812 matrix = nullptr;
2813 }
2814 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2815 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2816 picture->playback(this);
2817 } else {
2818 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002819 }
2820}
robertphillips9b14f262014-06-04 05:40:44 -07002821
reedd5fa1a42014-08-09 11:08:05 -07002822void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2823 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002824 if (!paint || paint->canComputeFastBounds()) {
2825 SkRect bounds = picture->cullRect();
2826 if (paint) {
2827 paint->computeFastBounds(bounds, &bounds);
2828 }
2829 if (matrix) {
2830 matrix->mapRect(&bounds);
2831 }
2832 if (this->quickReject(bounds)) {
2833 return;
2834 }
2835 }
2836
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002837 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002838 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839}
2840
vjiaoblack95302da2016-07-21 10:25:54 -07002841#ifdef SK_EXPERIMENTAL_SHADOWING
2842void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2843 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002844 const SkPaint* paint,
2845 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002846 RETURN_ON_NULL(picture);
2847
2848 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2849
vjiaoblacke6f5d562016-08-25 06:30:23 -07002850 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002851}
2852
2853void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2854 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002855 const SkPaint* paint,
2856 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002857 if (!paint || paint->canComputeFastBounds()) {
2858 SkRect bounds = picture->cullRect();
2859 if (paint) {
2860 paint->computeFastBounds(bounds, &bounds);
2861 }
2862 if (matrix) {
2863 matrix->mapRect(&bounds);
2864 }
2865 if (this->quickReject(bounds)) {
2866 return;
2867 }
2868 }
2869
2870 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2871
vjiaoblacke6f5d562016-08-25 06:30:23 -07002872 sk_sp<SkImage> povDepthMap;
2873 sk_sp<SkImage> diffuseMap;
2874
vjiaoblack904527d2016-08-09 09:32:09 -07002875 // povDepthMap
2876 {
2877 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002878 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2879 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002880 sk_sp<SkLights> povLight = builder.finish();
2881
2882 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2883 picture->cullRect().height(),
2884 kBGRA_8888_SkColorType,
2885 kOpaque_SkAlphaType);
2886
2887 // Create a new surface (that matches the backend of canvas)
2888 // to create the povDepthMap
2889 sk_sp<SkSurface> surf(this->makeSurface(info));
2890
2891 // Wrap another SPFCanvas around the surface
2892 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2893 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2894
2895 // set the depth map canvas to have the light as the user's POV
2896 depthMapCanvas->setLights(std::move(povLight));
2897
2898 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002899 povDepthMap = surf->makeImageSnapshot();
2900 }
2901
2902 // diffuseMap
2903 {
2904 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2905 picture->cullRect().height(),
2906 kBGRA_8888_SkColorType,
2907 kOpaque_SkAlphaType);
2908
2909 sk_sp<SkSurface> surf(this->makeSurface(info));
2910 surf->getCanvas()->drawPicture(picture);
2911
2912 diffuseMap = surf->makeImageSnapshot();
2913 }
vjiaoblack904527d2016-08-09 09:32:09 -07002914
Mike Reed0acd7952017-04-28 11:12:19 -04002915 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader();
2916 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader();
vjiaoblackb2796fd2016-09-09 09:22:39 -07002917
2918 // TODO: pass the depth to the shader in vertices, or uniforms
2919 // so we don't have to render depth and color separately
2920 for (int i = 0; i < fLights->numLights(); ++i) {
2921 // skip over ambient lights; they don't cast shadows
2922 // lights that have shadow maps do not need updating (because lights are immutable)
2923 sk_sp<SkImage> depthMap;
2924 SkISize shMapSize;
2925
2926 if (fLights->light(i).getShadowMap() != nullptr) {
2927 continue;
2928 }
2929
2930 if (fLights->light(i).isRadial()) {
2931 shMapSize.fHeight = 1;
2932 shMapSize.fWidth = (int) picture->cullRect().width();
2933
2934 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
2935 kBGRA_8888_SkColorType,
2936 kOpaque_SkAlphaType);
2937
2938 // Create new surface (that matches the backend of canvas)
2939 // for each shadow map
2940 sk_sp<SkSurface> surf(this->makeSurface(info));
2941
2942 // Wrap another SPFCanvas around the surface
2943 SkCanvas* depthMapCanvas = surf->getCanvas();
2944
2945 SkLights::Builder builder;
2946 builder.add(fLights->light(i));
2947 sk_sp<SkLights> curLight = builder.finish();
2948
2949 sk_sp<SkShader> shadowMapShader;
2950 shadowMapShader = SkRadialShadowMapShader::Make(
2951 povDepthShader, curLight,
2952 (int) picture->cullRect().width(),
2953 (int) picture->cullRect().height());
2954
2955 SkPaint shadowMapPaint;
2956 shadowMapPaint.setShader(std::move(shadowMapShader));
2957
2958 depthMapCanvas->setLights(curLight);
2959
2960 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
2961 diffuseMap->height()),
2962 shadowMapPaint);
2963
2964 depthMap = surf->makeImageSnapshot();
2965
2966 } else {
2967 // TODO: compute the correct size of the depth map from the light properties
2968 // TODO: maybe add a kDepth_8_SkColorType
2969 // TODO: find actual max depth of picture
2970 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
2971 fLights->light(i), 255,
2972 (int) picture->cullRect().width(),
2973 (int) picture->cullRect().height());
2974
2975 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
2976 kBGRA_8888_SkColorType,
2977 kOpaque_SkAlphaType);
2978
2979 // Create a new surface (that matches the backend of canvas)
2980 // for each shadow map
2981 sk_sp<SkSurface> surf(this->makeSurface(info));
2982
2983 // Wrap another SPFCanvas around the surface
2984 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2985 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2986 depthMapCanvas->setShadowParams(params);
2987
2988 // set the depth map canvas to have the light we're drawing.
2989 SkLights::Builder builder;
2990 builder.add(fLights->light(i));
2991 sk_sp<SkLights> curLight = builder.finish();
2992 depthMapCanvas->setLights(std::move(curLight));
2993
2994 depthMapCanvas->drawPicture(picture);
2995 depthMap = surf->makeImageSnapshot();
2996 }
2997
2998 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
2999 fLights->light(i).setShadowMap(std::move(depthMap));
3000 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3001 // we blur the variance map
3002 SkPaint blurPaint;
3003 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3004 params.fShadowRadius, nullptr));
3005
3006 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3007 kBGRA_8888_SkColorType,
3008 kOpaque_SkAlphaType);
3009
3010 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3011
3012 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3013
3014 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3015 }
3016 }
3017
3018 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003019 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3020 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003021 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003022 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003023 diffuseMap->height(),
3024 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003025
3026 shadowPaint.setShader(shadowShader);
3027
3028 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003029}
3030#endif
3031
reed@android.com8a1c16f2008-12-17 15:59:43 +00003032///////////////////////////////////////////////////////////////////////////////
3033///////////////////////////////////////////////////////////////////////////////
3034
reed3aafe112016-08-18 12:45:34 -07003035SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003036 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003037
3038 SkASSERT(canvas);
3039
reed3aafe112016-08-18 12:45:34 -07003040 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003041 fDone = !fImpl->next();
3042}
3043
3044SkCanvas::LayerIter::~LayerIter() {
3045 fImpl->~SkDrawIter();
3046}
3047
3048void SkCanvas::LayerIter::next() {
3049 fDone = !fImpl->next();
3050}
3051
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003052SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003053 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003054}
3055
3056const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003057 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003058}
3059
3060const SkPaint& SkCanvas::LayerIter::paint() const {
3061 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003062 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003063 paint = &fDefaultPaint;
3064 }
3065 return *paint;
3066}
3067
Mike Reeda1361362017-03-07 09:37:29 -05003068void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3069 return fImpl->fDevice->onAsRgnClip(rgn);
3070}
3071
reed@android.com8a1c16f2008-12-17 15:59:43 +00003072int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3073int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003074
3075///////////////////////////////////////////////////////////////////////////////
3076
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003077static bool supported_for_raster_canvas(const SkImageInfo& info) {
3078 switch (info.alphaType()) {
3079 case kPremul_SkAlphaType:
3080 case kOpaque_SkAlphaType:
3081 break;
3082 default:
3083 return false;
3084 }
3085
3086 switch (info.colorType()) {
3087 case kAlpha_8_SkColorType:
3088 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003089 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003090 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003091 break;
3092 default:
3093 return false;
3094 }
3095
3096 return true;
3097}
3098
Mike Reed5df49342016-11-12 08:06:55 -06003099std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3100 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003101 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003102 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003103 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003104
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003105 SkBitmap bitmap;
3106 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003107 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003108 }
Mike Reed5df49342016-11-12 08:06:55 -06003109 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003110}
reedd5fa1a42014-08-09 11:08:05 -07003111
3112///////////////////////////////////////////////////////////////////////////////
3113
3114SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003115 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003116 : fCanvas(canvas)
3117 , fSaveCount(canvas->getSaveCount())
3118{
bsalomon49f085d2014-09-05 13:34:00 -07003119 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003120 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003121 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003122 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003123 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003124 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003125 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003126 canvas->save();
3127 }
mtklein6cfa73a2014-08-13 13:33:49 -07003128
bsalomon49f085d2014-09-05 13:34:00 -07003129 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003130 canvas->concat(*matrix);
3131 }
3132}
3133
3134SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3135 fCanvas->restoreToCount(fSaveCount);
3136}
reede8f30622016-03-23 18:59:25 -07003137
Florin Malitaee424ac2016-12-01 12:47:59 -05003138///////////////////////////////////////////////////////////////////////////////
3139
3140SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3141 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3142
Florin Malita439ace92016-12-02 12:05:41 -05003143SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3144 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3145
Florin Malitaee424ac2016-12-01 12:47:59 -05003146SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3147 (void)this->INHERITED::getSaveLayerStrategy(rec);
3148 return kNoLayer_SaveLayerStrategy;
3149}
3150
3151///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003152
reed73603f32016-09-20 08:42:38 -07003153static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3154static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3155static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3156static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3157static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3158static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003159
3160///////////////////////////////////////////////////////////////////////////////////////////////////
3161
3162SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3163 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04003164 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05003165 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3166 SkIPoint origin = dev->getOrigin();
3167 SkMatrix ctm = this->getTotalMatrix();
3168 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3169
3170 SkIRect clip = fMCRec->fRasterClip.getBounds();
3171 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003172 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003173 clip.setEmpty();
3174 }
3175
3176 fAllocator->updateHandle(handle, ctm, clip);
3177 return handle;
3178 }
3179 return nullptr;
3180}
3181
3182static bool install(SkBitmap* bm, const SkImageInfo& info,
3183 const SkRasterHandleAllocator::Rec& rec) {
3184 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3185 rec.fReleaseProc, rec.fReleaseCtx);
3186}
3187
3188SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3189 SkBitmap* bm) {
3190 SkRasterHandleAllocator::Rec rec;
3191 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3192 return nullptr;
3193 }
3194 return rec.fHandle;
3195}
3196
3197std::unique_ptr<SkCanvas>
3198SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3199 const SkImageInfo& info, const Rec* rec) {
3200 if (!alloc || !supported_for_raster_canvas(info)) {
3201 return nullptr;
3202 }
3203
3204 SkBitmap bm;
3205 Handle hndl;
3206
3207 if (rec) {
3208 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3209 } else {
3210 hndl = alloc->allocBitmap(info, &bm);
3211 }
3212 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3213}