blob: c3e6aa6c7808b54a32be5ceed8ce824ebd874e8d [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"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000047#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070048#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050051#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050052#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
55
Mike Reed139e5e02017-03-08 11:29:33 -050056class SkNoPixelsDevice : public SkBaseDevice {
57public:
58 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
59 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
60 {}
61
62 void resetForNextPicture(const SkIRect& bounds) {
63 this->privateResize(bounds.width(), bounds.height());
64 }
65
66protected:
67 // We don't track the clip at all (for performance), but we have to respond to some queries.
68 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
69 void onSave() override {}
70 void onRestore() override {}
71 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
72 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
73 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
74 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
75 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
76 bool onClipIsAA() const override { return false; }
77 void onAsRgnClip(SkRegion* rgn) const override {
78 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
79 }
80 ClipType onGetClipType() const override {
81 return kRect_ClipType;
82 }
83
84 void drawPaint(const SkPaint& paint) override {}
85 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
86 void drawRect(const SkRect&, const SkPaint&) override {}
87 void drawOval(const SkRect&, const SkPaint&) override {}
88 void drawRRect(const SkRRect&, const SkPaint&) override {}
89 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
90 void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {}
91 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
92 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
93 SkCanvas::SrcRectConstraint) override {}
94 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
95 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
96 const SkPaint&) override {}
97 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
98 void drawVertices(SkCanvas::VertexMode, int, const SkPoint[], const SkPoint[], const SkColor[],
99 SkBlendMode, const uint16_t[], int, const SkPaint&) override {}
100
101private:
102 typedef SkBaseDevice INHERITED;
103};
104
105///////////////////////////////////////////////////////////////////////////////////////////////////
106
reedc83a2972015-07-16 07:40:45 -0700107/*
108 * Return true if the drawing this rect would hit every pixels in the canvas.
109 *
110 * Returns false if
111 * - rect does not contain the canvas' bounds
112 * - paint is not fill
113 * - paint would blur or otherwise change the coverage of the rect
114 */
115bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
116 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700117 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
118 (int)kNone_ShaderOverrideOpacity,
119 "need_matching_enums0");
120 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
121 (int)kOpaque_ShaderOverrideOpacity,
122 "need_matching_enums1");
123 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
124 (int)kNotOpaque_ShaderOverrideOpacity,
125 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700126
127 const SkISize size = this->getBaseLayerSize();
128 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500129
130 // if we're clipped at all, we can't overwrite the entire surface
131 {
132 SkBaseDevice* base = this->getDevice();
133 SkBaseDevice* top = this->getTopDevice();
134 if (base != top) {
135 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
136 }
137 if (!base->clipIsWideOpen()) {
138 return false;
139 }
reedc83a2972015-07-16 07:40:45 -0700140 }
141
142 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700143 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700144 return false; // conservative
145 }
halcanaryc5769b22016-08-10 07:13:21 -0700146
147 SkRect devRect;
148 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
149 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700150 return false;
151 }
152 }
153
154 if (paint) {
155 SkPaint::Style paintStyle = paint->getStyle();
156 if (!(paintStyle == SkPaint::kFill_Style ||
157 paintStyle == SkPaint::kStrokeAndFill_Style)) {
158 return false;
159 }
160 if (paint->getMaskFilter() || paint->getLooper()
161 || paint->getPathEffect() || paint->getImageFilter()) {
162 return false; // conservative
163 }
164 }
165 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
166}
167
168///////////////////////////////////////////////////////////////////////////////////////////////////
169
reedd990e2f2014-12-22 11:58:30 -0800170static bool gIgnoreSaveLayerBounds;
171void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
172 gIgnoreSaveLayerBounds = ignore;
173}
174bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
175 return gIgnoreSaveLayerBounds;
176}
177
reed0acf1b42014-12-22 16:12:38 -0800178static bool gTreatSpriteAsBitmap;
179void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
180 gTreatSpriteAsBitmap = spriteAsBitmap;
181}
182bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
183 return gTreatSpriteAsBitmap;
184}
185
reed@google.comda17f752012-08-16 18:27:05 +0000186// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187//#define SK_TRACE_SAVERESTORE
188
189#ifdef SK_TRACE_SAVERESTORE
190 static int gLayerCounter;
191 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
192 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
193
194 static int gRecCounter;
195 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
196 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
197
198 static int gCanvasCounter;
199 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
200 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
201#else
202 #define inc_layer()
203 #define dec_layer()
204 #define inc_rec()
205 #define dec_rec()
206 #define inc_canvas()
207 #define dec_canvas()
208#endif
209
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000210typedef SkTLazy<SkPaint> SkLazyPaint;
211
reedc83a2972015-07-16 07:40:45 -0700212void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000213 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700214 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
215 ? SkSurface::kDiscard_ContentChangeMode
216 : SkSurface::kRetain_ContentChangeMode);
217 }
218}
219
220void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
221 ShaderOverrideOpacity overrideOpacity) {
222 if (fSurfaceBase) {
223 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
224 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
225 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
226 // and therefore we don't care which mode we're in.
227 //
228 if (fSurfaceBase->outstandingImageSnapshot()) {
229 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
230 mode = SkSurface::kDiscard_ContentChangeMode;
231 }
232 }
233 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000234 }
235}
236
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000239/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 The clip/matrix/proc are fields that reflect the top of the save/restore
241 stack. Whenever the canvas changes, it marks a dirty flag, and then before
242 these are used (assuming we're not on a layer) we rebuild these cache
243 values: they reflect the top of the save stack, but translated and clipped
244 by the device's XY offset and bitmap-bounds.
245*/
246struct DeviceCM {
247 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000248 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000249 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000250 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700251 const SkMatrix* fMatrix;
252 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700253 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254
Mike Reeda1361362017-03-07 09:37:29 -0500255 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700256 : fNext(nullptr)
reed8c30a812016-04-20 16:36:51 -0700257 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700258 {
reed2c9e2002016-07-25 08:05:22 -0700259 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000260 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700261 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000262 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000264 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700265 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700266 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000267 }
reed@google.com4b226022011-01-11 18:32:13 +0000268
mtkleinfeaadee2015-04-08 11:25:48 -0700269 void reset(const SkIRect& bounds) {
270 SkASSERT(!fPaint);
271 SkASSERT(!fNext);
272 SkASSERT(fDevice);
273 fClip.setRect(bounds);
274 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275};
276
277/* This is the record we keep for each save/restore level in the stack.
278 Since a level optionally copies the matrix and/or stack, we have pointers
279 for these fields. If the value is copied for this level, the copy is
280 stored in the ...Storage field, and the pointer points to that. If the
281 value is not copied for this level, we ignore ...Storage, and just point
282 at the corresponding value in the previous level in the stack.
283*/
284class SkCanvas::MCRec {
285public:
reed1f836ee2014-07-07 07:49:34 -0700286 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700287 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288 /* If there are any layers in the stack, this points to the top-most
289 one that is at or below this level in the stack (so we know what
290 bitmap/device to draw into from this level. This value is NOT
291 reference counted, since the real owner is either our fLayer field,
292 or a previous one in a lower level.)
293 */
Mike Reeda1361362017-03-07 09:37:29 -0500294 DeviceCM* fTopLayer;
295 SkConservativeClip fRasterClip;
296 SkMatrix fMatrix;
297 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298
vjiaoblacke5de1302016-07-13 14:05:28 -0700299 // This is the current cumulative depth (aggregate of all done translateZ calls)
300 SkScalar fCurDrawDepth;
301
Mike Reeda1361362017-03-07 09:37:29 -0500302 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700303 fFilter = nullptr;
304 fLayer = nullptr;
305 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800306 fMatrix.reset();
307 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700308 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700309
reedd9544982014-09-09 18:46:22 -0700310 // don't bother initializing fNext
311 inc_rec();
312 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700313 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
314 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700315 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700316 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700317 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800318 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700319
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320 // don't bother initializing fNext
321 inc_rec();
322 }
323 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000324 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700325 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326 dec_rec();
327 }
mtkleinfeaadee2015-04-08 11:25:48 -0700328
329 void reset(const SkIRect& bounds) {
330 SkASSERT(fLayer);
331 SkASSERT(fDeferredSaveCount == 0);
332
333 fMatrix.reset();
334 fRasterClip.setRect(bounds);
335 fLayer->reset(bounds);
336 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337};
338
Mike Reeda1361362017-03-07 09:37:29 -0500339class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340public:
Mike Reeda1361362017-03-07 09:37:29 -0500341 SkDrawIter(SkCanvas* canvas)
342 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
343 {}
reed@google.com4b226022011-01-11 18:32:13 +0000344
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000346 const DeviceCM* rec = fCurrLayer;
347 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 fDevice = rec->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 fPaint = rec->fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700351 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 return true;
353 }
354 return false;
355 }
reed@google.com4b226022011-01-11 18:32:13 +0000356
reed@google.com6f8f2922011-03-04 22:27:10 +0000357 int getX() const { return fDevice->getOrigin().x(); }
358 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000360
Mike Reed99330ba2017-02-22 11:01:08 -0500361 SkBaseDevice* fDevice;
362
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 const DeviceCM* fCurrLayer;
365 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366};
367
Mike Reed7627fa52017-02-08 10:07:53 -0500368#define FOR_EACH_TOP_DEVICE( code ) \
369 do { \
370 DeviceCM* layer = fMCRec->fTopLayer; \
371 while (layer) { \
372 SkBaseDevice* device = layer->fDevice; \
Mike Reedc42a1cd2017-02-14 14:25:14 -0500373 if (device) { \
374 code; \
375 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500376 layer = layer->fNext; \
377 } \
378 } while (0)
379
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380/////////////////////////////////////////////////////////////////////////////
381
reeddbc3cef2015-04-29 12:18:57 -0700382static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
383 return lazy->isValid() ? lazy->get() : lazy->set(orig);
384}
385
386/**
387 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700388 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700389 */
reedd053ce92016-03-22 10:17:23 -0700390static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700391 SkImageFilter* imgf = paint.getImageFilter();
392 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700393 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700394 }
395
reedd053ce92016-03-22 10:17:23 -0700396 SkColorFilter* imgCFPtr;
397 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700398 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700399 }
reedd053ce92016-03-22 10:17:23 -0700400 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700401
402 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700403 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700404 // there is no existing paint colorfilter, so we can just return the imagefilter's
405 return imgCF;
406 }
407
408 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
409 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700410 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700411}
412
senorblanco87e066e2015-10-28 11:23:36 -0700413/**
414 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
415 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
416 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
417 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
418 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
419 * conservative "effective" bounds based on the settings in the paint... with one exception. This
420 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
421 * deliberately ignored.
422 */
423static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
424 const SkRect& rawBounds,
425 SkRect* storage) {
426 SkPaint tmpUnfiltered(paint);
427 tmpUnfiltered.setImageFilter(nullptr);
428 if (tmpUnfiltered.canComputeFastBounds()) {
429 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
430 } else {
431 return rawBounds;
432 }
433}
434
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435class AutoDrawLooper {
436public:
senorblanco87e066e2015-10-28 11:23:36 -0700437 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
438 // paint. It's used to determine the size of the offscreen layer for filters.
439 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700440 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700441 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000442 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800443#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800445#else
446 fFilter = nullptr;
447#endif
reed4a8126e2014-09-22 07:29:03 -0700448 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000449 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700450 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000451 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452
reedd053ce92016-03-22 10:17:23 -0700453 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700454 if (simplifiedCF) {
455 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700456 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700457 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700458 fPaint = paint;
459 }
460
461 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700462 /**
463 * We implement ImageFilters for a given draw by creating a layer, then applying the
464 * imagefilter to the pixels of that layer (its backing surface/image), and then
465 * we call restore() to xfer that layer to the main canvas.
466 *
467 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
468 * 2. Generate the src pixels:
469 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
470 * return (fPaint). We then draw the primitive (using srcover) into a cleared
471 * buffer/surface.
472 * 3. Restore the layer created in #1
473 * The imagefilter is passed the buffer/surface from the layer (now filled with the
474 * src pixels of the primitive). It returns a new "filtered" buffer, which we
475 * draw onto the previous layer using the xfermode from the original paint.
476 */
reed@google.com8926b162012-03-23 15:36:36 +0000477 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500478 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700479 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700480 SkRect storage;
481 if (rawBounds) {
482 // Make rawBounds include all paint outsets except for those due to image filters.
483 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
484 }
reedbfd5f172016-01-07 11:28:08 -0800485 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700486 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700487 fTempLayerForImageFilter = true;
488 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000489 }
490
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000491 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500492 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000493 fIsSimple = false;
494 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700495 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000496 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700497 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000498 }
499 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000500
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700502 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000503 fCanvas->internalRestore();
504 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000505 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000507
reed@google.com4e2b3d32011-04-07 14:18:59 +0000508 const SkPaint& paint() const {
509 SkASSERT(fPaint);
510 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000511 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000512
reed@google.com129ec222012-05-15 13:24:09 +0000513 bool next(SkDrawFilter::Type drawType) {
514 if (fDone) {
515 return false;
516 } else if (fIsSimple) {
517 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000518 return !fPaint->nothingToDraw();
519 } else {
520 return this->doNext(drawType);
521 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000522 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000523
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500525 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700526 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000527 SkCanvas* fCanvas;
528 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000529 SkDrawFilter* fFilter;
530 const SkPaint* fPaint;
531 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700532 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000533 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000534 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000535 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500536 char fStorage[48];
537 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000538
539 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540};
541
reed@google.com129ec222012-05-15 13:24:09 +0000542bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700543 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000544 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700545 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000546
reeddbc3cef2015-04-29 12:18:57 -0700547 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
548 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000549
reed5c476fb2015-04-20 08:04:21 -0700550 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700551 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700552 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000553 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000554
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000555 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000556 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000557 return false;
558 }
559 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000560 if (!fFilter->filter(paint, drawType)) {
561 fDone = true;
562 return false;
563 }
halcanary96fcdcc2015-08-27 07:41:13 -0700564 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000565 // no looper means we only draw once
566 fDone = true;
567 }
568 }
569 fPaint = paint;
570
571 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000572 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000573 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000574 }
575
576 // call this after any possible paint modifiers
577 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700578 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000579 return false;
580 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000581 return true;
582}
583
reed@android.com8a1c16f2008-12-17 15:59:43 +0000584////////// macros to place around the internal draw calls //////////////////
585
reed3aafe112016-08-18 12:45:34 -0700586#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
587 this->predrawNotify(); \
588 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
589 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800590 SkDrawIter iter(this);
591
592
reed@google.com8926b162012-03-23 15:36:36 +0000593#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000594 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700595 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000596 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000597 SkDrawIter iter(this);
598
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000599#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000600 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700601 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000602 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000604
reedc83a2972015-07-16 07:40:45 -0700605#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
606 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700607 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700608 while (looper.next(type)) { \
609 SkDrawIter iter(this);
610
reed@google.com4e2b3d32011-04-07 14:18:59 +0000611#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612
613////////////////////////////////////////////////////////////////////////////
614
msarettfbfa2582016-08-12 08:29:08 -0700615static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
616 if (bounds.isEmpty()) {
617 return SkRect::MakeEmpty();
618 }
619
620 // Expand bounds out by 1 in case we are anti-aliasing. We store the
621 // bounds as floats to enable a faster quick reject implementation.
622 SkRect dst;
623 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
624 return dst;
625}
626
mtkleinfeaadee2015-04-08 11:25:48 -0700627void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
628 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700629 fMCRec->reset(bounds);
630
631 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500632 // know that the device is a SkNoPixelsDevice.
633 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice)->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700634 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700635 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700636}
637
reedd9544982014-09-09 18:46:22 -0700638SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800639 if (device && device->forceConservativeRasterClip()) {
640 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
641 }
reed42b73eb2015-11-20 13:42:42 -0800642
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000643 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800644 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700645 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700646#ifdef SK_EXPERIMENTAL_SHADOWING
647 fLights = nullptr;
648#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649
650 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500651 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500652 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700653 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654
reeda499f902015-05-01 09:34:31 -0700655 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
656 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Mike Reeda1361362017-03-07 09:37:29 -0500657 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700658
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660
halcanary96fcdcc2015-08-27 07:41:13 -0700661 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000662
reedf92c8662014-08-18 08:02:43 -0700663 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700664 // The root device and the canvas should always have the same pixel geometry
665 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700666 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800667 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700668 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500669
Mike Reedc42a1cd2017-02-14 14:25:14 -0500670 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700671 }
msarettfbfa2582016-08-12 08:29:08 -0700672
reedf92c8662014-08-18 08:02:43 -0700673 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674}
675
reed@google.comcde92112011-07-06 20:00:52 +0000676SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000677 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700678 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000679{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000680 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000681
halcanary96fcdcc2015-08-27 07:41:13 -0700682 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000683}
684
reed96a857e2015-01-25 10:33:58 -0800685SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000686 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800687 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000688{
689 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700690
Mike Reed139e5e02017-03-08 11:29:33 -0500691 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(width, height), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700692 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700693}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000694
reed78e27682014-11-19 08:04:34 -0800695SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700696 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700697 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700698{
699 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700700
Mike Reed139e5e02017-03-08 11:29:33 -0500701 this->init(new SkNoPixelsDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700702}
703
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000704SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000705 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700706 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000707{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000708 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700709
reedd9544982014-09-09 18:46:22 -0700710 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000711}
712
robertphillipsfcf78292015-06-19 11:49:52 -0700713SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
714 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700715 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700716{
717 inc_canvas();
718
719 this->init(device, flags);
720}
721
reed4a8126e2014-09-22 07:29:03 -0700722SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700723 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700724 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700725{
726 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700727
Hal Canary704cd322016-11-07 14:13:52 -0500728 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
729 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700730}
reed29c857d2014-09-21 10:25:07 -0700731
Mike Reed356f7c22017-01-10 11:58:39 -0500732SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
733 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700734 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
735 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500736 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700737{
738 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700739
Mike Reed356f7c22017-01-10 11:58:39 -0500740 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500741 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742}
743
Mike Reed356f7c22017-01-10 11:58:39 -0500744SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
745
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746SkCanvas::~SkCanvas() {
747 // free up the contents of our deque
748 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000749
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750 this->internalRestore(); // restore the last, since we're going away
751
halcanary385fe4d2015-08-26 13:07:48 -0700752 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000753
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754 dec_canvas();
755}
756
fmalita53d9f1c2016-01-25 06:23:54 -0800757#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758SkDrawFilter* SkCanvas::getDrawFilter() const {
759 return fMCRec->fFilter;
760}
761
762SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700763 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
765 return filter;
766}
fmalita77650002016-01-21 18:47:11 -0800767#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000769SkMetaData& SkCanvas::getMetaData() {
770 // metadata users are rare, so we lazily allocate it. If that changes we
771 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700772 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000773 fMetaData = new SkMetaData;
774 }
775 return *fMetaData;
776}
777
reed@android.com8a1c16f2008-12-17 15:59:43 +0000778///////////////////////////////////////////////////////////////////////////////
779
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000780void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700781 this->onFlush();
782}
783
784void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000785 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000786 if (device) {
787 device->flush();
788 }
789}
790
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000791SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000792 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000793 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
794}
795
senorblancoafc7cce2016-02-02 18:44:15 -0800796SkIRect SkCanvas::getTopLayerBounds() const {
797 SkBaseDevice* d = this->getTopDevice();
798 if (!d) {
799 return SkIRect::MakeEmpty();
800 }
801 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
802}
803
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000804SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000806 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000807 SkASSERT(rec && rec->fLayer);
808 return rec->fLayer->fDevice;
809}
810
Florin Malita0ed3b642017-01-13 16:56:38 +0000811SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000812 return fMCRec->fTopLayer->fDevice;
813}
814
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000815bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000816 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700817 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700818 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000819 return false;
820 }
821 weAllocated = true;
822 }
823
reedcf01e312015-05-23 19:14:51 -0700824 SkAutoPixmapUnlock unlocker;
825 if (bitmap->requestLock(&unlocker)) {
826 const SkPixmap& pm = unlocker.pixmap();
827 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
828 return true;
829 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000830 }
831
832 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500833 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000834 }
835 return false;
836}
reed@google.com51df9e32010-12-23 19:29:18 +0000837
bsalomon@google.comc6980972011-11-02 19:57:21 +0000838bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000839 SkIRect r = srcRect;
840 const SkISize size = this->getBaseLayerSize();
841 if (!r.intersect(0, 0, size.width(), size.height())) {
842 bitmap->reset();
843 return false;
844 }
845
reed84825042014-09-02 12:50:45 -0700846 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000847 // bitmap will already be reset.
848 return false;
849 }
850 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
851 bitmap->reset();
852 return false;
853 }
854 return true;
855}
856
reed96472de2014-12-10 09:53:42 -0800857bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000858 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000859 if (!device) {
860 return false;
861 }
mtkleinf0f14112014-12-12 08:46:25 -0800862
Matt Sarett03dd6d52017-01-23 12:15:09 -0500863 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000864}
865
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000866bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700867 SkAutoPixmapUnlock unlocker;
868 if (bitmap.requestLock(&unlocker)) {
869 const SkPixmap& pm = unlocker.pixmap();
870 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000871 }
872 return false;
873}
874
Matt Sarett03dd6d52017-01-23 12:15:09 -0500875bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000876 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000877 SkBaseDevice* device = this->getDevice();
878 if (!device) {
879 return false;
880 }
881
Matt Sarett03dd6d52017-01-23 12:15:09 -0500882 // This check gives us an early out and prevents generation ID churn on the surface.
883 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
884 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
885 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
886 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000887 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000888
Matt Sarett03dd6d52017-01-23 12:15:09 -0500889 // Tell our owning surface to bump its generation ID.
890 const bool completeOverwrite =
891 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700892 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700893
Matt Sarett03dd6d52017-01-23 12:15:09 -0500894 // This can still fail, most notably in the case of a invalid color type or alpha type
895 // conversion. We could pull those checks into this function and avoid the unnecessary
896 // generation ID bump. But then we would be performing those checks twice, since they
897 // are also necessary at the bitmap/pixmap entry points.
898 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000899}
reed@google.com51df9e32010-12-23 19:29:18 +0000900
reed@android.com8a1c16f2008-12-17 15:59:43 +0000901//////////////////////////////////////////////////////////////////////////////
902
reed2ff1fce2014-12-11 07:07:37 -0800903void SkCanvas::checkForDeferredSave() {
904 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800905 this->doSave();
906 }
907}
908
reedf0090cb2014-11-26 08:55:51 -0800909int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800910#ifdef SK_DEBUG
911 int count = 0;
912 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
913 for (;;) {
914 const MCRec* rec = (const MCRec*)iter.next();
915 if (!rec) {
916 break;
917 }
918 count += 1 + rec->fDeferredSaveCount;
919 }
920 SkASSERT(count == fSaveCount);
921#endif
922 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800923}
924
925int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800926 fSaveCount += 1;
927 fMCRec->fDeferredSaveCount += 1;
928 return this->getSaveCount() - 1; // return our prev value
929}
930
931void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800932 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700933
934 SkASSERT(fMCRec->fDeferredSaveCount > 0);
935 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800936 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800937}
938
939void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800940 if (fMCRec->fDeferredSaveCount > 0) {
941 SkASSERT(fSaveCount > 1);
942 fSaveCount -= 1;
943 fMCRec->fDeferredSaveCount -= 1;
944 } else {
945 // check for underflow
946 if (fMCStack.count() > 1) {
947 this->willRestore();
948 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700949 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800950 this->internalRestore();
951 this->didRestore();
952 }
reedf0090cb2014-11-26 08:55:51 -0800953 }
954}
955
956void SkCanvas::restoreToCount(int count) {
957 // sanity check
958 if (count < 1) {
959 count = 1;
960 }
mtkleinf0f14112014-12-12 08:46:25 -0800961
reedf0090cb2014-11-26 08:55:51 -0800962 int n = this->getSaveCount() - count;
963 for (int i = 0; i < n; ++i) {
964 this->restore();
965 }
966}
967
reed2ff1fce2014-12-11 07:07:37 -0800968void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700970 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000972
Mike Reedc42a1cd2017-02-14 14:25:14 -0500973 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974}
975
reed4960eee2015-12-18 07:09:18 -0800976bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800977 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978}
979
reed4960eee2015-12-18 07:09:18 -0800980bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700981 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500982 SkIRect clipBounds = this->getDeviceClipBounds();
983 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000984 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000985 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000986
reed96e657d2015-03-10 17:30:07 -0700987 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
988
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000989 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700990 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800991 if (bounds && !imageFilter->canComputeFastBounds()) {
992 bounds = nullptr;
993 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000994 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000995 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700996 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000997 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000998
reed96e657d2015-03-10 17:30:07 -0700999 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001000 r.roundOut(&ir);
1001 // early exit if the layer's bounds are clipped out
1002 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001003 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -05001004 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -07001005 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001006 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001007 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001008 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001009 }
1010 } else { // no user bounds, so just use the clip
1011 ir = clipBounds;
1012 }
reed180aec42015-03-11 10:39:04 -07001013 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014
reed4960eee2015-12-18 07:09:18 -08001015 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001016 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -07001017 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001018 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001019 }
1020
1021 if (intersection) {
1022 *intersection = ir;
1023 }
1024 return true;
1025}
1026
reed4960eee2015-12-18 07:09:18 -08001027
reed4960eee2015-12-18 07:09:18 -08001028int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1029 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001030}
1031
reed70ee31b2015-12-10 13:44:45 -08001032int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001033 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1034}
1035
1036int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1037 SaveLayerRec rec(origRec);
1038 if (gIgnoreSaveLayerBounds) {
1039 rec.fBounds = nullptr;
1040 }
1041 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1042 fSaveCount += 1;
1043 this->internalSaveLayer(rec, strategy);
1044 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001045}
1046
reeda2217ef2016-07-20 06:04:34 -07001047void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001048 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001049 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001050 SkDraw draw;
1051 SkRasterClip rc;
1052 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1053 if (!dst->accessPixels(&draw.fDst)) {
1054 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001055 }
reeda2217ef2016-07-20 06:04:34 -07001056 draw.fMatrix = &SkMatrix::I();
1057 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001058
1059 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001060 if (filter) {
1061 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1062 }
reeda2217ef2016-07-20 06:04:34 -07001063
Mike Reedc42a1cd2017-02-14 14:25:14 -05001064 int x = src->getOrigin().x() - dstOrigin.x();
1065 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001066 auto special = src->snapSpecial();
1067 if (special) {
Mike Reeda1361362017-03-07 09:37:29 -05001068 dst->drawSpecial(special.get(), x, y, p);
reeda2217ef2016-07-20 06:04:34 -07001069 }
robertphillips7354a4b2015-12-16 05:08:27 -08001070}
reed70ee31b2015-12-10 13:44:45 -08001071
reed129ed1c2016-02-22 06:42:31 -08001072static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1073 const SkPaint* paint) {
1074 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1075 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001076 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001077 const bool hasImageFilter = paint && paint->getImageFilter();
1078
1079 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1080 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1081 // force to L32
1082 return SkImageInfo::MakeN32(w, h, alphaType);
1083 } else {
1084 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001085 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001086 }
1087}
1088
reed4960eee2015-12-18 07:09:18 -08001089void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1090 const SkRect* bounds = rec.fBounds;
1091 const SkPaint* paint = rec.fPaint;
1092 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1093
reed8c30a812016-04-20 16:36:51 -07001094 SkLazyPaint lazyP;
1095 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1096 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001097 SkMatrix remainder;
1098 SkSize scale;
1099 /*
1100 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1101 * but they do handle scaling. To accommodate this, we do the following:
1102 *
1103 * 1. Stash off the current CTM
1104 * 2. Decompose the CTM into SCALE and REMAINDER
1105 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1106 * contains the REMAINDER
1107 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1108 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1109 * of the original imagefilter, and draw that (via drawSprite)
1110 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1111 *
1112 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1113 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1114 */
reed96a04f32016-04-25 09:25:15 -07001115 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001116 stashedMatrix.decomposeScale(&scale, &remainder))
1117 {
1118 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1119 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1120 SkPaint* p = lazyP.set(*paint);
1121 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1122 SkFilterQuality::kLow_SkFilterQuality,
1123 sk_ref_sp(imageFilter)));
1124 imageFilter = p->getImageFilter();
1125 paint = p;
1126 }
reed8c30a812016-04-20 16:36:51 -07001127
junov@chromium.orga907ac32012-02-24 21:54:07 +00001128 // do this before we create the layer. We don't call the public save() since
1129 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001130 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001131
junov@chromium.orga907ac32012-02-24 21:54:07 +00001132 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001133 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001134 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001135 }
1136
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001137 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1138 // the clipRectBounds() call above?
1139 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001140 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001141 }
1142
reed4960eee2015-12-18 07:09:18 -08001143 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001144 SkPixelGeometry geo = fProps.pixelGeometry();
1145 if (paint) {
reed76033be2015-03-14 10:54:31 -07001146 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001147 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001148 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001149 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001150 }
1151 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001152
robertphillips5139e502016-07-19 05:10:40 -07001153 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001154 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001155 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001156 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001157 }
reedb2db8982014-11-13 12:41:02 -08001158
robertphillips5139e502016-07-19 05:10:40 -07001159 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001160 paint);
1161
Hal Canary704cd322016-11-07 14:13:52 -05001162 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001163 {
reed70ee31b2015-12-10 13:44:45 -08001164 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001165 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001166 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001167 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001168 preserveLCDText,
1169 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001170 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1171 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001172 return;
reed61f501f2015-04-29 08:34:00 -07001173 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001174 }
Hal Canary704cd322016-11-07 14:13:52 -05001175 DeviceCM* layer =
Mike Reeda1361362017-03-07 09:37:29 -05001176 new DeviceCM(newDevice.get(), paint, this, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001177
Mike Reedb43a3e02017-02-11 10:18:58 -05001178 // only have a "next" if this new layer doesn't affect the clip (rare)
1179 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180 fMCRec->fLayer = layer;
1181 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001182
Mike Reedc61abee2017-02-28 17:45:27 -05001183 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001184 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001185 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001186 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001187
Mike Reedc42a1cd2017-02-14 14:25:14 -05001188 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1189
1190 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1191 if (layer->fNext) {
1192 // need to punch a hole in the previous device, so we don't draw there, given that
1193 // the new top-layer will allow drawing to happen "below" it.
1194 SkRegion hole(ir);
1195 do {
1196 layer = layer->fNext;
1197 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1198 } while (layer->fNext);
1199 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200}
1201
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001202int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001203 if (0xFF == alpha) {
1204 return this->saveLayer(bounds, nullptr);
1205 } else {
1206 SkPaint tmpPaint;
1207 tmpPaint.setAlpha(alpha);
1208 return this->saveLayer(bounds, &tmpPaint);
1209 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001210}
1211
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212void SkCanvas::internalRestore() {
1213 SkASSERT(fMCStack.count() != 0);
1214
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001215 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216 DeviceCM* layer = fMCRec->fLayer; // may be null
1217 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001218 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001219
1220 // now do the normal restore()
1221 fMCRec->~MCRec(); // balanced in save()
1222 fMCStack.pop_back();
1223 fMCRec = (MCRec*)fMCStack.back();
1224
Mike Reedc42a1cd2017-02-14 14:25:14 -05001225 if (fMCRec) {
1226 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1227 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001228
reed@android.com8a1c16f2008-12-17 15:59:43 +00001229 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1230 since if we're being recorded, we don't want to record this (the
1231 recorder will have already recorded the restore).
1232 */
bsalomon49f085d2014-09-05 13:34:00 -07001233 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001234 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001235 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001236 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001237 // restore what we smashed in internalSaveLayer
1238 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001239 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001240 delete layer;
reedb679ca82015-04-07 04:40:48 -07001241 } else {
1242 // we're at the root
reeda499f902015-05-01 09:34:31 -07001243 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001244 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001245 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001247 }
msarettfbfa2582016-08-12 08:29:08 -07001248
1249 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001250 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001251 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1252 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253}
1254
reede8f30622016-03-23 18:59:25 -07001255sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001256 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001257 props = &fProps;
1258 }
1259 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001260}
1261
reede8f30622016-03-23 18:59:25 -07001262sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001263 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001264 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001265}
1266
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001267SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001268 return this->onImageInfo();
1269}
1270
1271SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001272 SkBaseDevice* dev = this->getDevice();
1273 if (dev) {
1274 return dev->imageInfo();
1275 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001276 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001277 }
1278}
1279
brianosman898235c2016-04-06 07:38:23 -07001280bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001281 return this->onGetProps(props);
1282}
1283
1284bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001285 SkBaseDevice* dev = this->getDevice();
1286 if (dev) {
1287 if (props) {
1288 *props = fProps;
1289 }
1290 return true;
1291 } else {
1292 return false;
1293 }
1294}
1295
reed6ceeebd2016-03-09 14:26:26 -08001296bool SkCanvas::peekPixels(SkPixmap* pmap) {
1297 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001298}
1299
reed884e97c2015-05-26 11:31:54 -07001300bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001301 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001302 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001303}
1304
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001305void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001306 SkPixmap pmap;
1307 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001308 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001309 }
1310 if (info) {
1311 *info = pmap.info();
1312 }
1313 if (rowBytes) {
1314 *rowBytes = pmap.rowBytes();
1315 }
1316 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001317 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001318 }
reed884e97c2015-05-26 11:31:54 -07001319 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001320}
1321
reed884e97c2015-05-26 11:31:54 -07001322bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001323 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001324 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001325}
1326
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328
reed7503d602016-07-15 14:23:29 -07001329void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001330 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001331 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 paint = &tmp;
1333 }
reed@google.com4b226022011-01-11 18:32:13 +00001334
reed@google.com8926b162012-03-23 15:36:36 +00001335 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001336
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001338 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001339 paint = &looper.paint();
1340 SkImageFilter* filter = paint->getImageFilter();
1341 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001342 if (filter) {
1343 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1344 if (specialImage) {
Mike Reeda1361362017-03-07 09:37:29 -05001345 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint);
Robert Phillips833dcf42016-11-18 08:44:13 -05001346 }
reed@google.com76dd2772012-01-05 21:15:07 +00001347 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001348 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001349 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 }
reeda2217ef2016-07-20 06:04:34 -07001351
reed@google.com4e2b3d32011-04-07 14:18:59 +00001352 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001353}
1354
reed32704672015-12-16 08:27:10 -08001355/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001356
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001357void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001358 if (dx || dy) {
1359 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001360 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001361
reedfe69b502016-09-12 06:31:48 -07001362 // Translate shouldn't affect the is-scale-translateness of the matrix.
1363 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001364
Mike Reedc42a1cd2017-02-14 14:25:14 -05001365 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001366
reedfe69b502016-09-12 06:31:48 -07001367 this->didTranslate(dx,dy);
1368 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001369}
1370
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001371void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001372 SkMatrix m;
1373 m.setScale(sx, sy);
1374 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001375}
1376
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001377void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001378 SkMatrix m;
1379 m.setRotate(degrees);
1380 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381}
1382
bungeman7438bfc2016-07-12 15:01:19 -07001383void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1384 SkMatrix m;
1385 m.setRotate(degrees, px, py);
1386 this->concat(m);
1387}
1388
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001389void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001390 SkMatrix m;
1391 m.setSkew(sx, sy);
1392 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001393}
1394
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001395void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001396 if (matrix.isIdentity()) {
1397 return;
1398 }
1399
reed2ff1fce2014-12-11 07:07:37 -08001400 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001401 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001402 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001403
Mike Reed7627fa52017-02-08 10:07:53 -05001404 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001405
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001406 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001407}
1408
reed8c30a812016-04-20 16:36:51 -07001409void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001410 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001411 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001412
Mike Reedc42a1cd2017-02-14 14:25:14 -05001413 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001414}
1415
1416void SkCanvas::setMatrix(const SkMatrix& matrix) {
1417 this->checkForDeferredSave();
1418 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001419 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420}
1421
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001423 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424}
1425
vjiaoblack95302da2016-07-21 10:25:54 -07001426#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001427void SkCanvas::translateZ(SkScalar z) {
1428 this->checkForDeferredSave();
1429 this->fMCRec->fCurDrawDepth += z;
1430 this->didTranslateZ(z);
1431}
1432
1433SkScalar SkCanvas::getZ() const {
1434 return this->fMCRec->fCurDrawDepth;
1435}
1436
vjiaoblack95302da2016-07-21 10:25:54 -07001437void SkCanvas::setLights(sk_sp<SkLights> lights) {
1438 this->fLights = lights;
1439}
1440
1441sk_sp<SkLights> SkCanvas::getLights() const {
1442 return this->fLights;
1443}
1444#endif
1445
reed@android.com8a1c16f2008-12-17 15:59:43 +00001446//////////////////////////////////////////////////////////////////////////////
1447
Mike Reedc1f77742016-12-09 09:00:50 -05001448void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001449 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001450 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1451 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001452}
1453
Mike Reedc1f77742016-12-09 09:00:50 -05001454void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001455 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001456
Mike Reed7627fa52017-02-08 10:07:53 -05001457 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001458
reedc64eff52015-11-21 12:39:45 -08001459 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001460 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1461 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001462 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001463}
1464
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001465void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1466 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001467 if (fClipRestrictionRect.isEmpty()) {
1468 // we notify the device, but we *dont* resolve deferred saves (since we're just
1469 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001470 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001471 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001472 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001473 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001474 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001475 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001476 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1477 }
1478}
1479
Mike Reedc1f77742016-12-09 09:00:50 -05001480void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001481 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001482 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001483 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001484 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1485 } else {
1486 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001487 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001488}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001489
Mike Reedc1f77742016-12-09 09:00:50 -05001490void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001491 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001492
Brian Salomona3b45d42016-10-03 11:36:16 -04001493 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001494
Mike Reed7627fa52017-02-08 10:07:53 -05001495 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001496
Brian Salomona3b45d42016-10-03 11:36:16 -04001497 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1498 isAA);
1499 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001500}
1501
Mike Reedc1f77742016-12-09 09:00:50 -05001502void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001503 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001504 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001505
1506 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1507 SkRect r;
1508 if (path.isRect(&r)) {
1509 this->onClipRect(r, op, edgeStyle);
1510 return;
1511 }
1512 SkRRect rrect;
1513 if (path.isOval(&r)) {
1514 rrect.setOval(r);
1515 this->onClipRRect(rrect, op, edgeStyle);
1516 return;
1517 }
1518 if (path.isRRect(&rrect)) {
1519 this->onClipRRect(rrect, op, edgeStyle);
1520 return;
1521 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001522 }
robertphillips39f05382015-11-24 09:30:12 -08001523
1524 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001525}
1526
Mike Reedc1f77742016-12-09 09:00:50 -05001527void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001528 AutoValidateClip avc(this);
1529
Brian Salomona3b45d42016-10-03 11:36:16 -04001530 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001531
Mike Reed7627fa52017-02-08 10:07:53 -05001532 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001533
Brian Salomona3b45d42016-10-03 11:36:16 -04001534 const SkPath* rasterClipPath = &path;
1535 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001536 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1537 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001538 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001539}
1540
Mike Reedc1f77742016-12-09 09:00:50 -05001541void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001542 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001543 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001544}
1545
Mike Reedc1f77742016-12-09 09:00:50 -05001546void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001547 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001548
reed@google.com5c3d1472011-02-22 19:12:23 +00001549 AutoValidateClip avc(this);
1550
reed73603f32016-09-20 08:42:38 -07001551 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001552 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001553}
1554
reed@google.com819c9212011-02-23 18:56:55 +00001555#ifdef SK_DEBUG
1556void SkCanvas::validateClip() const {
1557 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001558 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001559 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001560 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001561 return;
1562 }
reed@google.com819c9212011-02-23 18:56:55 +00001563}
1564#endif
1565
reed@google.com90c07ea2012-04-13 13:50:27 +00001566void SkCanvas::replayClips(ClipVisitor* visitor) const {
Mike Reeda1361362017-03-07 09:37:29 -05001567#if 0
reed687fa1c2015-04-07 08:00:56 -07001568 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001569 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001570
halcanary96fcdcc2015-08-27 07:41:13 -07001571 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001572 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001573 }
Mike Reeda1361362017-03-07 09:37:29 -05001574#endif
1575}
1576
1577bool SkCanvas::androidFramework_isClipAA() const {
1578 bool containsAA = false;
1579
1580 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1581
1582 return containsAA;
1583}
1584
1585class RgnAccumulator {
1586 SkRegion* fRgn;
1587public:
1588 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1589 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1590 SkIPoint origin = device->getOrigin();
1591 if (origin.x() | origin.y()) {
1592 rgn->translate(origin.x(), origin.y());
1593 }
1594 fRgn->op(*rgn, SkRegion::kUnion_Op);
1595 }
1596};
1597
1598void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1599 RgnAccumulator accum(rgn);
1600 SkRegion tmp;
1601
1602 rgn->setEmpty();
1603 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001604}
1605
reed@google.com5c3d1472011-02-22 19:12:23 +00001606///////////////////////////////////////////////////////////////////////////////
1607
reed@google.com754de5f2014-02-24 19:38:20 +00001608bool SkCanvas::isClipEmpty() const {
Mike Reeda1361362017-03-07 09:37:29 -05001609 SkBaseDevice* dev = this->getTopDevice();
1610 // if no device we return true
1611 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
reed@google.com754de5f2014-02-24 19:38:20 +00001612}
1613
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001614bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001615 SkBaseDevice* dev = this->getTopDevice();
1616 // if no device we return false
1617 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001618}
1619
msarettfbfa2582016-08-12 08:29:08 -07001620static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1621#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1622 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1623 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1624 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1625 return 0xF != _mm_movemask_ps(mask);
1626#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1627 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1628 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1629 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1630 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1631#else
1632 SkRect devRectAsRect;
1633 SkRect devClipAsRect;
1634 devRect.store(&devRectAsRect.fLeft);
1635 devClip.store(&devClipAsRect.fLeft);
1636 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1637#endif
1638}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001639
msarettfbfa2582016-08-12 08:29:08 -07001640// It's important for this function to not be inlined. Otherwise the compiler will share code
1641// between the fast path and the slow path, resulting in two slow paths.
1642static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1643 const SkMatrix& matrix) {
1644 SkRect deviceRect;
1645 matrix.mapRect(&deviceRect, src);
1646 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1647}
1648
1649bool SkCanvas::quickReject(const SkRect& src) const {
1650#ifdef SK_DEBUG
1651 // Verify that fDeviceClipBounds are set properly.
1652 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001653 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001654 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001655 } else {
msarettfbfa2582016-08-12 08:29:08 -07001656 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657 }
msarettfbfa2582016-08-12 08:29:08 -07001658
msarett9637ea92016-08-18 14:03:30 -07001659 // Verify that fIsScaleTranslate is set properly.
1660 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001661#endif
1662
msarett9637ea92016-08-18 14:03:30 -07001663 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001664 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1665 }
1666
1667 // We inline the implementation of mapScaleTranslate() for the fast path.
1668 float sx = fMCRec->fMatrix.getScaleX();
1669 float sy = fMCRec->fMatrix.getScaleY();
1670 float tx = fMCRec->fMatrix.getTranslateX();
1671 float ty = fMCRec->fMatrix.getTranslateY();
1672 Sk4f scale(sx, sy, sx, sy);
1673 Sk4f trans(tx, ty, tx, ty);
1674
1675 // Apply matrix.
1676 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1677
1678 // Make sure left < right, top < bottom.
1679 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1680 Sk4f min = Sk4f::Min(ltrb, rblt);
1681 Sk4f max = Sk4f::Max(ltrb, rblt);
1682 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1683 // ARM this sequence generates the fastest (a single instruction).
1684 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1685
1686 // Check if the device rect is NaN or outside the clip.
1687 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001688}
1689
reed@google.com3b3e8952012-08-16 20:53:31 +00001690bool SkCanvas::quickReject(const SkPath& path) const {
1691 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692}
1693
Mike Reed42e8c532017-01-23 14:09:13 -05001694SkRect SkCanvas::onGetLocalClipBounds() const {
1695 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001696 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001697 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001698 }
1699
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001700 SkMatrix inverse;
1701 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001702 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001703 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001704 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001705
Mike Reed42e8c532017-01-23 14:09:13 -05001706 SkRect bounds;
1707 SkRect r;
1708 // adjust it outwards in case we are antialiasing
1709 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001710
Mike Reed42e8c532017-01-23 14:09:13 -05001711 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1712 ibounds.fRight + inset, ibounds.fBottom + inset);
1713 inverse.mapRect(&bounds, r);
1714 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001715}
1716
Mike Reed42e8c532017-01-23 14:09:13 -05001717SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001718 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001719}
1720
reed@android.com8a1c16f2008-12-17 15:59:43 +00001721const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001722 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001723}
1724
Brian Osman11052242016-10-27 14:47:55 -04001725GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001726 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001727 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001728}
1729
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001730GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001731 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001732 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001733}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001734
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001735void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1736 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001737 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001738 if (outer.isEmpty()) {
1739 return;
1740 }
1741 if (inner.isEmpty()) {
1742 this->drawRRect(outer, paint);
1743 return;
1744 }
1745
1746 // We don't have this method (yet), but technically this is what we should
1747 // be able to assert...
1748 // SkASSERT(outer.contains(inner));
1749 //
1750 // For now at least check for containment of bounds
1751 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1752
1753 this->onDrawDRRect(outer, inner, paint);
1754}
1755
reed41af9662015-01-05 07:49:08 -08001756// These need to stop being virtual -- clients need to override the onDraw... versions
1757
1758void SkCanvas::drawPaint(const SkPaint& paint) {
1759 this->onDrawPaint(paint);
1760}
1761
1762void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1763 this->onDrawRect(r, paint);
1764}
1765
msarettdca352e2016-08-26 06:37:45 -07001766void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1767 if (region.isEmpty()) {
1768 return;
1769 }
1770
1771 if (region.isRect()) {
1772 return this->drawIRect(region.getBounds(), paint);
1773 }
1774
1775 this->onDrawRegion(region, paint);
1776}
1777
reed41af9662015-01-05 07:49:08 -08001778void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1779 this->onDrawOval(r, paint);
1780}
1781
1782void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1783 this->onDrawRRect(rrect, paint);
1784}
1785
1786void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1787 this->onDrawPoints(mode, count, pts, paint);
1788}
1789
1790void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001791 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001792 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001793 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1794 indexCount, paint);
1795}
1796
1797void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1798 uint32_t flags) {
1799 RETURN_ON_NULL(vertices);
1800 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001801}
1802
1803void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1804 this->onDrawPath(path, paint);
1805}
1806
reeda85d4d02015-05-06 12:56:48 -07001807void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001808 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001809 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001810}
1811
reede47829b2015-08-06 10:02:53 -07001812void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1813 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001814 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001815 if (dst.isEmpty() || src.isEmpty()) {
1816 return;
1817 }
1818 this->onDrawImageRect(image, &src, dst, paint, constraint);
1819}
reed41af9662015-01-05 07:49:08 -08001820
reed84984ef2015-07-17 07:09:43 -07001821void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1822 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001823 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001824 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001825}
1826
reede47829b2015-08-06 10:02:53 -07001827void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1828 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001829 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001830 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1831 constraint);
1832}
reede47829b2015-08-06 10:02:53 -07001833
reed4c21dc52015-06-25 12:32:03 -07001834void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1835 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001836 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001837 if (dst.isEmpty()) {
1838 return;
1839 }
msarett552bca92016-08-03 06:53:26 -07001840 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1841 this->onDrawImageNine(image, center, dst, paint);
1842 } else {
reede47829b2015-08-06 10:02:53 -07001843 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001844 }
reed4c21dc52015-06-25 12:32:03 -07001845}
1846
msarett16882062016-08-16 09:31:08 -07001847void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1848 const SkPaint* paint) {
1849 RETURN_ON_NULL(image);
1850 if (dst.isEmpty()) {
1851 return;
1852 }
msarett71df2d72016-09-30 12:41:42 -07001853
1854 SkIRect bounds;
1855 Lattice latticePlusBounds = lattice;
1856 if (!latticePlusBounds.fBounds) {
1857 bounds = SkIRect::MakeWH(image->width(), image->height());
1858 latticePlusBounds.fBounds = &bounds;
1859 }
1860
1861 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1862 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001863 } else {
1864 this->drawImageRect(image, dst, paint);
1865 }
1866}
1867
reed41af9662015-01-05 07:49:08 -08001868void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001869 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001870 return;
1871 }
reed41af9662015-01-05 07:49:08 -08001872 this->onDrawBitmap(bitmap, dx, dy, paint);
1873}
1874
reede47829b2015-08-06 10:02:53 -07001875void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001876 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001877 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001878 return;
1879 }
reede47829b2015-08-06 10:02:53 -07001880 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001881}
1882
reed84984ef2015-07-17 07:09:43 -07001883void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1884 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001885 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001886}
1887
reede47829b2015-08-06 10:02:53 -07001888void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1889 SrcRectConstraint constraint) {
1890 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1891 constraint);
1892}
reede47829b2015-08-06 10:02:53 -07001893
reed41af9662015-01-05 07:49:08 -08001894void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1895 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001896 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001897 return;
1898 }
msarett552bca92016-08-03 06:53:26 -07001899 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1900 this->onDrawBitmapNine(bitmap, center, dst, paint);
1901 } else {
reeda5517e22015-07-14 10:54:12 -07001902 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001903 }
reed41af9662015-01-05 07:49:08 -08001904}
1905
msarettc573a402016-08-02 08:05:56 -07001906void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1907 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001908 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001909 return;
1910 }
msarett71df2d72016-09-30 12:41:42 -07001911
1912 SkIRect bounds;
1913 Lattice latticePlusBounds = lattice;
1914 if (!latticePlusBounds.fBounds) {
1915 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1916 latticePlusBounds.fBounds = &bounds;
1917 }
1918
1919 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1920 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001921 } else {
msarett16882062016-08-16 09:31:08 -07001922 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001923 }
msarettc573a402016-08-02 08:05:56 -07001924}
1925
reed71c3c762015-06-24 10:29:17 -07001926void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001927 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001928 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001929 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001930 if (count <= 0) {
1931 return;
1932 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001933 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001934 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001935 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001936}
1937
reedf70b5312016-03-04 16:36:20 -08001938void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1939 if (key) {
1940 this->onDrawAnnotation(rect, key, value);
1941 }
1942}
1943
reede47829b2015-08-06 10:02:53 -07001944void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1945 const SkPaint* paint, SrcRectConstraint constraint) {
1946 if (src) {
1947 this->drawImageRect(image, *src, dst, paint, constraint);
1948 } else {
1949 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1950 dst, paint, constraint);
1951 }
1952}
1953void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1954 const SkPaint* paint, SrcRectConstraint constraint) {
1955 if (src) {
1956 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1957 } else {
1958 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1959 dst, paint, constraint);
1960 }
1961}
1962
tomhudsoncb3bd182016-05-18 07:24:16 -07001963void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1964 SkIRect layer_bounds = this->getTopLayerBounds();
1965 if (matrix) {
1966 *matrix = this->getTotalMatrix();
1967 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1968 }
1969 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001970 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001971 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1972 }
1973}
1974
reed@android.com8a1c16f2008-12-17 15:59:43 +00001975//////////////////////////////////////////////////////////////////////////////
1976// These are the virtual drawing methods
1977//////////////////////////////////////////////////////////////////////////////
1978
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001979void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001980 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001981 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1982 }
1983}
1984
reed41af9662015-01-05 07:49:08 -08001985void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001986 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001987 this->internalDrawPaint(paint);
1988}
1989
1990void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001991 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001992
1993 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001994 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001995 }
1996
reed@google.com4e2b3d32011-04-07 14:18:59 +00001997 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998}
1999
reed41af9662015-01-05 07:49:08 -08002000void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2001 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002002 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002003 if ((long)count <= 0) {
2004 return;
2005 }
2006
Mike Reed822128b2017-02-28 16:41:03 -05002007 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002008 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002009 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002010 // special-case 2 points (common for drawing a single line)
2011 if (2 == count) {
2012 r.set(pts[0], pts[1]);
2013 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002014 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002015 }
Mike Reed822128b2017-02-28 16:41:03 -05002016 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002017 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2018 return;
2019 }
2020 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002021 }
reed@google.coma584aed2012-05-16 14:06:02 +00002022
halcanary96fcdcc2015-08-27 07:41:13 -07002023 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002024
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002025 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002026
reed@android.com8a1c16f2008-12-17 15:59:43 +00002027 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002028 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002029 }
reed@google.com4b226022011-01-11 18:32:13 +00002030
reed@google.com4e2b3d32011-04-07 14:18:59 +00002031 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002032}
2033
reed4a167172016-08-18 17:15:25 -07002034static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2035 return ((intptr_t)paint.getImageFilter() |
2036#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2037 (intptr_t)canvas->getDrawFilter() |
2038#endif
2039 (intptr_t)paint.getLooper() ) != 0;
2040}
2041
reed41af9662015-01-05 07:49:08 -08002042void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002043 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002044 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002045 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2046 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2047 SkRect tmp(r);
2048 tmp.sort();
2049
Mike Reed822128b2017-02-28 16:41:03 -05002050 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002051 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2052 return;
2053 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002054 }
reed@google.com4b226022011-01-11 18:32:13 +00002055
reed4a167172016-08-18 17:15:25 -07002056 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002057 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002058
reed4a167172016-08-18 17:15:25 -07002059 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002060 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002061 }
2062
2063 LOOPER_END
2064 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002065 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002066 SkDrawIter iter(this);
2067 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002068 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002069 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002070 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002071}
2072
msarett44df6512016-08-25 13:54:30 -07002073void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002074 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002075 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002076 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002077 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2078 return;
2079 }
msarett44df6512016-08-25 13:54:30 -07002080 }
2081
Mike Reed822128b2017-02-28 16:41:03 -05002082 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002083
2084 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002085 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002086 }
2087
2088 LOOPER_END
2089}
2090
reed41af9662015-01-05 07:49:08 -08002091void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002092 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002093 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002094 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002095 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2096 return;
2097 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002098 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002099
Mike Reed822128b2017-02-28 16:41:03 -05002100 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002101
2102 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002103 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002104 }
2105
2106 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002107}
2108
bsalomonac3aa242016-08-19 11:25:19 -07002109void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2110 SkScalar sweepAngle, bool useCenter,
2111 const SkPaint& paint) {
2112 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002113 if (paint.canComputeFastBounds()) {
2114 SkRect storage;
2115 // Note we're using the entire oval as the bounds.
2116 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2117 return;
2118 }
bsalomonac3aa242016-08-19 11:25:19 -07002119 }
2120
Mike Reed822128b2017-02-28 16:41:03 -05002121 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002122
2123 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002124 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002125 }
2126
2127 LOOPER_END
2128}
2129
reed41af9662015-01-05 07:49:08 -08002130void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002131 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002132 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002133 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002134 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2135 return;
2136 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002137 }
2138
2139 if (rrect.isRect()) {
2140 // call the non-virtual version
2141 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002142 return;
2143 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002144 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002145 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2146 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002147 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002148
Mike Reed822128b2017-02-28 16:41:03 -05002149 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002150
2151 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002152 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002153 }
2154
2155 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002156}
2157
Mike Reed822128b2017-02-28 16:41:03 -05002158void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002159 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002160 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002161 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2162 return;
2163 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002164 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002165
Mike Reed822128b2017-02-28 16:41:03 -05002166 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002167
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002168 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002169 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002170 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002171
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002172 LOOPER_END
2173}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002174
reed41af9662015-01-05 07:49:08 -08002175void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002176 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002177 if (!path.isFinite()) {
2178 return;
2179 }
2180
Mike Reed822128b2017-02-28 16:41:03 -05002181 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002182 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002183 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002184 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2185 return;
2186 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002187 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002188
Mike Reed822128b2017-02-28 16:41:03 -05002189 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002190 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002191 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002192 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002193 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002194 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002195
Mike Reed822128b2017-02-28 16:41:03 -05002196 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002197
2198 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002199 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002200 }
2201
reed@google.com4e2b3d32011-04-07 14:18:59 +00002202 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002203}
2204
reed262a71b2015-12-05 13:07:27 -08002205bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002206 if (!paint.getImageFilter()) {
2207 return false;
2208 }
2209
2210 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002211 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002212 return false;
2213 }
2214
2215 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2216 // Once we can filter and the filter will return a result larger than itself, we should be
2217 // able to remove this constraint.
2218 // skbug.com/4526
2219 //
2220 SkPoint pt;
2221 ctm.mapXY(x, y, &pt);
2222 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2223 return ir.contains(fMCRec->fRasterClip.getBounds());
2224}
2225
reeda85d4d02015-05-06 12:56:48 -07002226void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002227 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002228 SkRect bounds = SkRect::MakeXYWH(x, y,
2229 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002230 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002231 SkRect tmp = bounds;
2232 if (paint) {
2233 paint->computeFastBounds(tmp, &tmp);
2234 }
2235 if (this->quickReject(tmp)) {
2236 return;
2237 }
reeda85d4d02015-05-06 12:56:48 -07002238 }
halcanary9d524f22016-03-29 09:03:52 -07002239
reeda85d4d02015-05-06 12:56:48 -07002240 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002241 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002242 paint = lazy.init();
2243 }
reed262a71b2015-12-05 13:07:27 -08002244
reeda2217ef2016-07-20 06:04:34 -07002245 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002246 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2247 *paint);
2248 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002249 special = this->getDevice()->makeSpecial(image);
2250 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002251 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002252 }
2253 }
2254
reed262a71b2015-12-05 13:07:27 -08002255 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2256
reeda85d4d02015-05-06 12:56:48 -07002257 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002258 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002259 if (special) {
2260 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002261 iter.fDevice->ctm().mapXY(x, y, &pt);
2262 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002263 SkScalarRoundToInt(pt.fX),
2264 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002265 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002266 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002267 }
reeda85d4d02015-05-06 12:56:48 -07002268 }
halcanary9d524f22016-03-29 09:03:52 -07002269
reeda85d4d02015-05-06 12:56:48 -07002270 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002271}
2272
reed41af9662015-01-05 07:49:08 -08002273void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002274 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002275 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002276 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002277 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002278 if (paint) {
2279 paint->computeFastBounds(dst, &storage);
2280 }
2281 if (this->quickReject(storage)) {
2282 return;
2283 }
reeda85d4d02015-05-06 12:56:48 -07002284 }
2285 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002286 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002287 paint = lazy.init();
2288 }
halcanary9d524f22016-03-29 09:03:52 -07002289
senorblancoc41e7e12015-12-07 12:51:30 -08002290 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002291 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002292
reeda85d4d02015-05-06 12:56:48 -07002293 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002294 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002295 }
halcanary9d524f22016-03-29 09:03:52 -07002296
reeda85d4d02015-05-06 12:56:48 -07002297 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002298}
2299
reed41af9662015-01-05 07:49:08 -08002300void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002301 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302 SkDEBUGCODE(bitmap.validate();)
2303
reed33366972015-10-08 09:22:02 -07002304 if (bitmap.drawsNothing()) {
2305 return;
2306 }
2307
2308 SkLazyPaint lazy;
2309 if (nullptr == paint) {
2310 paint = lazy.init();
2311 }
2312
Mike Reed822128b2017-02-28 16:41:03 -05002313 SkRect bounds;
2314 bitmap.getBounds(&bounds);
2315 bounds.offset(x, y);
2316 bool canFastBounds = paint->canComputeFastBounds();
2317 if (canFastBounds) {
2318 SkRect storage;
2319 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002320 return;
2321 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002322 }
reed@google.com4b226022011-01-11 18:32:13 +00002323
reeda2217ef2016-07-20 06:04:34 -07002324 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002325 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2326 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002327 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002328 special = this->getDevice()->makeSpecial(bitmap);
2329 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002330 drawAsSprite = false;
2331 }
2332 }
2333
Mike Reed822128b2017-02-28 16:41:03 -05002334 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2335
2336 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002337
2338 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002339 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002340 if (special) {
reed262a71b2015-12-05 13:07:27 -08002341 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002342 iter.fDevice->ctm().mapXY(x, y, &pt);
2343 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002344 SkScalarRoundToInt(pt.fX),
2345 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002346 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002347 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002348 }
reed33366972015-10-08 09:22:02 -07002349 }
msarettfbfa2582016-08-12 08:29:08 -07002350
reed33366972015-10-08 09:22:02 -07002351 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352}
2353
reed@google.com9987ec32011-09-07 11:57:52 +00002354// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002355void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002356 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002357 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002358 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002359 return;
2360 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002361
halcanary96fcdcc2015-08-27 07:41:13 -07002362 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002363 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002364 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2365 return;
2366 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002367 }
reed@google.com3d608122011-11-21 15:16:16 +00002368
reed@google.com33535f32012-09-25 15:37:50 +00002369 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002370 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002371 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002372 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002373
senorblancoc41e7e12015-12-07 12:51:30 -08002374 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002375 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002376
reed@google.com33535f32012-09-25 15:37:50 +00002377 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002378 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002379 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002380
reed@google.com33535f32012-09-25 15:37:50 +00002381 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002382}
2383
reed41af9662015-01-05 07:49:08 -08002384void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002385 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002387 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002388 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002389}
2390
reed4c21dc52015-06-25 12:32:03 -07002391void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2392 const SkPaint* paint) {
2393 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002394
halcanary96fcdcc2015-08-27 07:41:13 -07002395 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002396 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002397 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2398 return;
2399 }
reed@google.com3d608122011-11-21 15:16:16 +00002400 }
halcanary9d524f22016-03-29 09:03:52 -07002401
reed4c21dc52015-06-25 12:32:03 -07002402 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002403 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002404 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002405 }
halcanary9d524f22016-03-29 09:03:52 -07002406
senorblancoc41e7e12015-12-07 12:51:30 -08002407 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002408
reed4c21dc52015-06-25 12:32:03 -07002409 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002410 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002411 }
halcanary9d524f22016-03-29 09:03:52 -07002412
reed4c21dc52015-06-25 12:32:03 -07002413 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002414}
2415
reed41af9662015-01-05 07:49:08 -08002416void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2417 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002418 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002419 SkDEBUGCODE(bitmap.validate();)
2420
halcanary96fcdcc2015-08-27 07:41:13 -07002421 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002422 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002423 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2424 return;
2425 }
reed4c21dc52015-06-25 12:32:03 -07002426 }
halcanary9d524f22016-03-29 09:03:52 -07002427
reed4c21dc52015-06-25 12:32:03 -07002428 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002429 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002430 paint = lazy.init();
2431 }
halcanary9d524f22016-03-29 09:03:52 -07002432
senorblancoc41e7e12015-12-07 12:51:30 -08002433 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002434
reed4c21dc52015-06-25 12:32:03 -07002435 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002436 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002437 }
halcanary9d524f22016-03-29 09:03:52 -07002438
reed4c21dc52015-06-25 12:32:03 -07002439 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002440}
2441
msarett16882062016-08-16 09:31:08 -07002442void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2443 const SkPaint* paint) {
2444 if (nullptr == paint || paint->canComputeFastBounds()) {
2445 SkRect storage;
2446 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2447 return;
2448 }
2449 }
2450
2451 SkLazyPaint lazy;
2452 if (nullptr == paint) {
2453 paint = lazy.init();
2454 }
2455
2456 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2457
2458 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002459 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002460 }
2461
2462 LOOPER_END
2463}
2464
2465void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2466 const SkRect& dst, const SkPaint* paint) {
2467 if (nullptr == paint || paint->canComputeFastBounds()) {
2468 SkRect storage;
2469 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2470 return;
2471 }
2472 }
2473
2474 SkLazyPaint lazy;
2475 if (nullptr == paint) {
2476 paint = lazy.init();
2477 }
2478
2479 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2480
2481 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002482 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002483 }
2484
2485 LOOPER_END
2486}
2487
reed@google.comf67e4cf2011-03-15 20:56:58 +00002488class SkDeviceFilteredPaint {
2489public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002490 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002491 uint32_t filteredFlags = device->filterTextFlags(paint);
2492 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002493 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002494 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002495 fPaint = newPaint;
2496 } else {
2497 fPaint = &paint;
2498 }
2499 }
2500
reed@google.comf67e4cf2011-03-15 20:56:58 +00002501 const SkPaint& paint() const { return *fPaint; }
2502
2503private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002504 const SkPaint* fPaint;
2505 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002506};
2507
reed@google.come0d9ce82014-04-23 04:00:17 +00002508void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2509 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002510 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002511
2512 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->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002515 }
2516
reed@google.com4e2b3d32011-04-07 14:18:59 +00002517 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002518}
2519
reed@google.come0d9ce82014-04-23 04:00:17 +00002520void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2521 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002522 SkPoint textOffset = SkPoint::Make(0, 0);
2523
halcanary96fcdcc2015-08-27 07:41:13 -07002524 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002525
reed@android.com8a1c16f2008-12-17 15:59:43 +00002526 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002527 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002528 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002529 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002530 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002531
reed@google.com4e2b3d32011-04-07 14:18:59 +00002532 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002533}
2534
reed@google.come0d9ce82014-04-23 04:00:17 +00002535void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2536 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002537
2538 SkPoint textOffset = SkPoint::Make(0, constY);
2539
halcanary96fcdcc2015-08-27 07:41:13 -07002540 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002541
reed@android.com8a1c16f2008-12-17 15:59:43 +00002542 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002543 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002544 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002545 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002546 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002547
reed@google.com4e2b3d32011-04-07 14:18:59 +00002548 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002549}
2550
reed@google.come0d9ce82014-04-23 04:00:17 +00002551void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2552 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002553 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002554
reed@android.com8a1c16f2008-12-17 15:59:43 +00002555 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002556 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002557 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002558 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002559
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002560 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002561}
2562
reed45561a02016-07-07 12:47:17 -07002563void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2564 const SkRect* cullRect, const SkPaint& paint) {
2565 if (cullRect && this->quickReject(*cullRect)) {
2566 return;
2567 }
2568
2569 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2570
2571 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002572 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002573 }
2574
2575 LOOPER_END
2576}
2577
fmalita00d5c2c2014-08-21 08:53:26 -07002578void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2579 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002580
fmalita85d5eb92015-03-04 11:20:12 -08002581 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002582 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002583 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002584 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002585 SkRect tmp;
2586 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2587 return;
2588 }
2589 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002590 }
2591
fmalita024f9962015-03-03 19:08:17 -08002592 // We cannot filter in the looper as we normally do, because the paint is
2593 // incomplete at this point (text-related attributes are embedded within blob run paints).
2594 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002595 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002596
fmalita85d5eb92015-03-04 11:20:12 -08002597 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002598
fmalitaaa1b9122014-08-28 14:32:24 -07002599 while (iter.next()) {
2600 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002601 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002602 }
2603
fmalitaaa1b9122014-08-28 14:32:24 -07002604 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002605
2606 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002607}
2608
reed@google.come0d9ce82014-04-23 04:00:17 +00002609// These will become non-virtual, so they always call the (virtual) onDraw... method
2610void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2611 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002612 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002613 if (byteLength) {
2614 this->onDrawText(text, byteLength, x, y, paint);
2615 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002616}
2617void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2618 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002619 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002620 if (byteLength) {
2621 this->onDrawPosText(text, byteLength, pos, paint);
2622 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002623}
2624void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2625 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002626 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002627 if (byteLength) {
2628 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2629 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002630}
2631void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2632 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002633 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002634 if (byteLength) {
2635 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2636 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002637}
reed45561a02016-07-07 12:47:17 -07002638void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2639 const SkRect* cullRect, const SkPaint& paint) {
2640 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2641 if (byteLength) {
2642 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2643 }
2644}
fmalita00d5c2c2014-08-21 08:53:26 -07002645void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2646 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002647 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002648 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002649 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002650}
reed@google.come0d9ce82014-04-23 04:00:17 +00002651
reed41af9662015-01-05 07:49:08 -08002652void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2653 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002654 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002655 const uint16_t indices[], int indexCount,
2656 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002657 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002658 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002659
reed@android.com8a1c16f2008-12-17 15:59:43 +00002660 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002661 iter.fDevice->drawVertices(vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002662 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002663 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002664 }
reed@google.com4b226022011-01-11 18:32:13 +00002665
reed@google.com4e2b3d32011-04-07 14:18:59 +00002666 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002667}
2668
Brian Salomon199fb872017-02-06 09:41:10 -05002669void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2670 const SkPaint& paint, uint32_t flags) {
2671 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2672 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2673
2674 while (iter.next()) {
2675 // In the common case of one iteration we could std::move vertices here.
Mike Reeda1361362017-03-07 09:37:29 -05002676 iter.fDevice->drawVerticesObject(vertices, bmode, looper.paint(), flags);
Brian Salomon199fb872017-02-06 09:41:10 -05002677 }
2678
2679 LOOPER_END
2680}
2681
2682void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2683 const SkPaint& paint, uint32_t flags) {
2684 const SkPoint* texs =
2685 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2686 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2687 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2688 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2689}
2690
dandovb3c9d1c2014-08-12 08:34:29 -07002691void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002692 const SkPoint texCoords[4], SkBlendMode bmode,
2693 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002694 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002695 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002696 return;
2697 }
mtklein6cfa73a2014-08-13 13:33:49 -07002698
Mike Reedfaba3712016-11-03 14:45:31 -04002699 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002700}
2701
2702void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002703 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002704 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002705 // Since a patch is always within the convex hull of the control points, we discard it when its
2706 // bounding rectangle is completely outside the current clip.
2707 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002708 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002709 if (this->quickReject(bounds)) {
2710 return;
2711 }
mtklein6cfa73a2014-08-13 13:33:49 -07002712
halcanary96fcdcc2015-08-27 07:41:13 -07002713 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002714
dandovecfff212014-08-04 10:02:00 -07002715 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002716 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002717 }
mtklein6cfa73a2014-08-13 13:33:49 -07002718
dandovecfff212014-08-04 10:02:00 -07002719 LOOPER_END
2720}
2721
reeda8db7282015-07-07 10:22:31 -07002722void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002723 RETURN_ON_NULL(dr);
2724 if (x || y) {
2725 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2726 this->onDrawDrawable(dr, &matrix);
2727 } else {
2728 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002729 }
2730}
2731
reeda8db7282015-07-07 10:22:31 -07002732void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002733 RETURN_ON_NULL(dr);
2734 if (matrix && matrix->isIdentity()) {
2735 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002736 }
reede3b38ce2016-01-08 09:18:44 -08002737 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002738}
2739
2740void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002741 // drawable bounds are no longer reliable (e.g. android displaylist)
2742 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002743 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002744}
2745
reed71c3c762015-06-24 10:29:17 -07002746void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002747 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002748 const SkRect* cull, const SkPaint* paint) {
2749 if (cull && this->quickReject(*cull)) {
2750 return;
2751 }
2752
2753 SkPaint pnt;
2754 if (paint) {
2755 pnt = *paint;
2756 }
halcanary9d524f22016-03-29 09:03:52 -07002757
halcanary96fcdcc2015-08-27 07:41:13 -07002758 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002759 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002760 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002761 }
2762 LOOPER_END
2763}
2764
reedf70b5312016-03-04 16:36:20 -08002765void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2766 SkASSERT(key);
2767
2768 SkPaint paint;
2769 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2770 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002771 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002772 }
2773 LOOPER_END
2774}
2775
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776//////////////////////////////////////////////////////////////////////////////
2777// These methods are NOT virtual, and therefore must call back into virtual
2778// methods, rather than actually drawing themselves.
2779//////////////////////////////////////////////////////////////////////////////
2780
Mike Reed3661bc92017-02-22 13:21:42 -05002781#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed374772b2016-10-05 17:33:02 -07002782void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002783 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784 SkPaint paint;
2785
2786 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002787 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002788 this->drawPaint(paint);
2789}
Mike Reed3661bc92017-02-22 13:21:42 -05002790#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791
reed374772b2016-10-05 17:33:02 -07002792void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794 SkPaint paint;
2795
2796 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002797 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798 this->drawPaint(paint);
2799}
2800
2801void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002802 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002803 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002804 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2805}
2806
Mike Reed3661bc92017-02-22 13:21:42 -05002807#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002808void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002809 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002810 SkPoint pt;
2811 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002812
reed@android.com8a1c16f2008-12-17 15:59:43 +00002813 pt.set(x, y);
2814 paint.setColor(color);
2815 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2816}
Mike Reed3661bc92017-02-22 13:21:42 -05002817#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002818
Mike Reed3661bc92017-02-22 13:21:42 -05002819void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002820 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002821 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002822
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823 pts[0].set(x0, y0);
2824 pts[1].set(x1, y1);
2825 this->drawPoints(kLines_PointMode, 2, pts, paint);
2826}
2827
Mike Reed3661bc92017-02-22 13:21:42 -05002828#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002829void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2830 SkScalar right, SkScalar bottom,
2831 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002832 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833 SkRect r;
2834
2835 r.set(left, top, right, bottom);
2836 this->drawRect(r, paint);
2837}
Mike Reed3661bc92017-02-22 13:21:42 -05002838#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839
Mike Reed3661bc92017-02-22 13:21:42 -05002840void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002841 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842 if (radius < 0) {
2843 radius = 0;
2844 }
2845
2846 SkRect r;
2847 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002848 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849}
2850
2851void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2852 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002853 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002854 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002855 SkRRect rrect;
2856 rrect.setRectXY(r, rx, ry);
2857 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002858 } else {
2859 this->drawRect(r, paint);
2860 }
2861}
2862
reed@android.com8a1c16f2008-12-17 15:59:43 +00002863void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2864 SkScalar sweepAngle, bool useCenter,
2865 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002866 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002867 if (oval.isEmpty() || !sweepAngle) {
2868 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002869 }
bsalomon21af9ca2016-08-25 12:29:23 -07002870 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002871}
2872
2873void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2874 const SkPath& path, SkScalar hOffset,
2875 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002876 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002877 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002878
reed@android.com8a1c16f2008-12-17 15:59:43 +00002879 matrix.setTranslate(hOffset, vOffset);
2880 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2881}
2882
reed@android.comf76bacf2009-05-13 14:00:33 +00002883///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002884
2885/**
2886 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2887 * against the playback cost of recursing into the subpicture to get at its actual ops.
2888 *
2889 * For now we pick a conservatively small value, though measurement (and other heuristics like
2890 * the type of ops contained) may justify changing this value.
2891 */
2892#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002893
reedd5fa1a42014-08-09 11:08:05 -07002894void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002895 RETURN_ON_NULL(picture);
2896
reed1c2c4412015-04-30 13:09:24 -07002897 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002898 if (matrix && matrix->isIdentity()) {
2899 matrix = nullptr;
2900 }
2901 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2902 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2903 picture->playback(this);
2904 } else {
2905 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002906 }
2907}
robertphillips9b14f262014-06-04 05:40:44 -07002908
reedd5fa1a42014-08-09 11:08:05 -07002909void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2910 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002911 if (!paint || paint->canComputeFastBounds()) {
2912 SkRect bounds = picture->cullRect();
2913 if (paint) {
2914 paint->computeFastBounds(bounds, &bounds);
2915 }
2916 if (matrix) {
2917 matrix->mapRect(&bounds);
2918 }
2919 if (this->quickReject(bounds)) {
2920 return;
2921 }
2922 }
2923
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002924 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002925 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002926}
2927
vjiaoblack95302da2016-07-21 10:25:54 -07002928#ifdef SK_EXPERIMENTAL_SHADOWING
2929void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2930 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002931 const SkPaint* paint,
2932 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002933 RETURN_ON_NULL(picture);
2934
2935 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2936
vjiaoblacke6f5d562016-08-25 06:30:23 -07002937 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002938}
2939
2940void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2941 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002942 const SkPaint* paint,
2943 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002944 if (!paint || paint->canComputeFastBounds()) {
2945 SkRect bounds = picture->cullRect();
2946 if (paint) {
2947 paint->computeFastBounds(bounds, &bounds);
2948 }
2949 if (matrix) {
2950 matrix->mapRect(&bounds);
2951 }
2952 if (this->quickReject(bounds)) {
2953 return;
2954 }
2955 }
2956
2957 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2958
vjiaoblacke6f5d562016-08-25 06:30:23 -07002959 sk_sp<SkImage> povDepthMap;
2960 sk_sp<SkImage> diffuseMap;
2961
vjiaoblack904527d2016-08-09 09:32:09 -07002962 // povDepthMap
2963 {
2964 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002965 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2966 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002967 sk_sp<SkLights> povLight = builder.finish();
2968
2969 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2970 picture->cullRect().height(),
2971 kBGRA_8888_SkColorType,
2972 kOpaque_SkAlphaType);
2973
2974 // Create a new surface (that matches the backend of canvas)
2975 // to create the povDepthMap
2976 sk_sp<SkSurface> surf(this->makeSurface(info));
2977
2978 // Wrap another SPFCanvas around the surface
2979 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2980 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2981
2982 // set the depth map canvas to have the light as the user's POV
2983 depthMapCanvas->setLights(std::move(povLight));
2984
2985 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002986 povDepthMap = surf->makeImageSnapshot();
2987 }
2988
2989 // diffuseMap
2990 {
2991 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2992 picture->cullRect().height(),
2993 kBGRA_8888_SkColorType,
2994 kOpaque_SkAlphaType);
2995
2996 sk_sp<SkSurface> surf(this->makeSurface(info));
2997 surf->getCanvas()->drawPicture(picture);
2998
2999 diffuseMap = surf->makeImageSnapshot();
3000 }
vjiaoblack904527d2016-08-09 09:32:09 -07003001
3002 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3003 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003004 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3005 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003006
3007 // TODO: pass the depth to the shader in vertices, or uniforms
3008 // so we don't have to render depth and color separately
3009 for (int i = 0; i < fLights->numLights(); ++i) {
3010 // skip over ambient lights; they don't cast shadows
3011 // lights that have shadow maps do not need updating (because lights are immutable)
3012 sk_sp<SkImage> depthMap;
3013 SkISize shMapSize;
3014
3015 if (fLights->light(i).getShadowMap() != nullptr) {
3016 continue;
3017 }
3018
3019 if (fLights->light(i).isRadial()) {
3020 shMapSize.fHeight = 1;
3021 shMapSize.fWidth = (int) picture->cullRect().width();
3022
3023 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3024 kBGRA_8888_SkColorType,
3025 kOpaque_SkAlphaType);
3026
3027 // Create new surface (that matches the backend of canvas)
3028 // for each shadow map
3029 sk_sp<SkSurface> surf(this->makeSurface(info));
3030
3031 // Wrap another SPFCanvas around the surface
3032 SkCanvas* depthMapCanvas = surf->getCanvas();
3033
3034 SkLights::Builder builder;
3035 builder.add(fLights->light(i));
3036 sk_sp<SkLights> curLight = builder.finish();
3037
3038 sk_sp<SkShader> shadowMapShader;
3039 shadowMapShader = SkRadialShadowMapShader::Make(
3040 povDepthShader, curLight,
3041 (int) picture->cullRect().width(),
3042 (int) picture->cullRect().height());
3043
3044 SkPaint shadowMapPaint;
3045 shadowMapPaint.setShader(std::move(shadowMapShader));
3046
3047 depthMapCanvas->setLights(curLight);
3048
3049 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3050 diffuseMap->height()),
3051 shadowMapPaint);
3052
3053 depthMap = surf->makeImageSnapshot();
3054
3055 } else {
3056 // TODO: compute the correct size of the depth map from the light properties
3057 // TODO: maybe add a kDepth_8_SkColorType
3058 // TODO: find actual max depth of picture
3059 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3060 fLights->light(i), 255,
3061 (int) picture->cullRect().width(),
3062 (int) picture->cullRect().height());
3063
3064 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3065 kBGRA_8888_SkColorType,
3066 kOpaque_SkAlphaType);
3067
3068 // Create a new surface (that matches the backend of canvas)
3069 // for each shadow map
3070 sk_sp<SkSurface> surf(this->makeSurface(info));
3071
3072 // Wrap another SPFCanvas around the surface
3073 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3074 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3075 depthMapCanvas->setShadowParams(params);
3076
3077 // set the depth map canvas to have the light we're drawing.
3078 SkLights::Builder builder;
3079 builder.add(fLights->light(i));
3080 sk_sp<SkLights> curLight = builder.finish();
3081 depthMapCanvas->setLights(std::move(curLight));
3082
3083 depthMapCanvas->drawPicture(picture);
3084 depthMap = surf->makeImageSnapshot();
3085 }
3086
3087 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3088 fLights->light(i).setShadowMap(std::move(depthMap));
3089 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3090 // we blur the variance map
3091 SkPaint blurPaint;
3092 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3093 params.fShadowRadius, nullptr));
3094
3095 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3096 kBGRA_8888_SkColorType,
3097 kOpaque_SkAlphaType);
3098
3099 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3100
3101 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3102
3103 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3104 }
3105 }
3106
3107 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003108 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3109 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003110 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003111 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003112 diffuseMap->height(),
3113 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003114
3115 shadowPaint.setShader(shadowShader);
3116
3117 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003118}
3119#endif
3120
reed@android.com8a1c16f2008-12-17 15:59:43 +00003121///////////////////////////////////////////////////////////////////////////////
3122///////////////////////////////////////////////////////////////////////////////
3123
reed3aafe112016-08-18 12:45:34 -07003124SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003125 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003126
3127 SkASSERT(canvas);
3128
reed3aafe112016-08-18 12:45:34 -07003129 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003130 fDone = !fImpl->next();
3131}
3132
3133SkCanvas::LayerIter::~LayerIter() {
3134 fImpl->~SkDrawIter();
3135}
3136
3137void SkCanvas::LayerIter::next() {
3138 fDone = !fImpl->next();
3139}
3140
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003141SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003142 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003143}
3144
3145const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003146 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003147}
3148
3149const SkPaint& SkCanvas::LayerIter::paint() const {
3150 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003151 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003152 paint = &fDefaultPaint;
3153 }
3154 return *paint;
3155}
3156
Mike Reeda1361362017-03-07 09:37:29 -05003157void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3158 return fImpl->fDevice->onAsRgnClip(rgn);
3159}
3160
reed@android.com8a1c16f2008-12-17 15:59:43 +00003161int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3162int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003163
3164///////////////////////////////////////////////////////////////////////////////
3165
fmalitac3b589a2014-06-05 12:40:07 -07003166SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003167
3168///////////////////////////////////////////////////////////////////////////////
3169
3170static bool supported_for_raster_canvas(const SkImageInfo& info) {
3171 switch (info.alphaType()) {
3172 case kPremul_SkAlphaType:
3173 case kOpaque_SkAlphaType:
3174 break;
3175 default:
3176 return false;
3177 }
3178
3179 switch (info.colorType()) {
3180 case kAlpha_8_SkColorType:
3181 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003182 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003183 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003184 break;
3185 default:
3186 return false;
3187 }
3188
3189 return true;
3190}
3191
Mike Reed5df49342016-11-12 08:06:55 -06003192std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3193 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003194 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003195 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003196 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003197
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003198 SkBitmap bitmap;
3199 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003200 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003201 }
Mike Reed5df49342016-11-12 08:06:55 -06003202 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003203}
reedd5fa1a42014-08-09 11:08:05 -07003204
3205///////////////////////////////////////////////////////////////////////////////
3206
3207SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003208 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003209 : fCanvas(canvas)
3210 , fSaveCount(canvas->getSaveCount())
3211{
bsalomon49f085d2014-09-05 13:34:00 -07003212 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003213 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003214 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003215 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003216 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003217 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003218 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003219 canvas->save();
3220 }
mtklein6cfa73a2014-08-13 13:33:49 -07003221
bsalomon49f085d2014-09-05 13:34:00 -07003222 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003223 canvas->concat(*matrix);
3224 }
3225}
3226
3227SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3228 fCanvas->restoreToCount(fSaveCount);
3229}
reede8f30622016-03-23 18:59:25 -07003230
Florin Malitaee424ac2016-12-01 12:47:59 -05003231///////////////////////////////////////////////////////////////////////////////
3232
3233SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3234 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3235
Florin Malita439ace92016-12-02 12:05:41 -05003236SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3237 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3238
Florin Malitaee424ac2016-12-01 12:47:59 -05003239SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3240 (void)this->INHERITED::getSaveLayerStrategy(rec);
3241 return kNoLayer_SaveLayerStrategy;
3242}
3243
3244///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003245
reed73603f32016-09-20 08:42:38 -07003246static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3247static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3248static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3249static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3250static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3251static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003252
3253///////////////////////////////////////////////////////////////////////////////////////////////////
3254
3255SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3256 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3257 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3258 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3259 SkIPoint origin = dev->getOrigin();
3260 SkMatrix ctm = this->getTotalMatrix();
3261 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3262
3263 SkIRect clip = fMCRec->fRasterClip.getBounds();
3264 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003265 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003266 clip.setEmpty();
3267 }
3268
3269 fAllocator->updateHandle(handle, ctm, clip);
3270 return handle;
3271 }
3272 return nullptr;
3273}
3274
3275static bool install(SkBitmap* bm, const SkImageInfo& info,
3276 const SkRasterHandleAllocator::Rec& rec) {
3277 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3278 rec.fReleaseProc, rec.fReleaseCtx);
3279}
3280
3281SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3282 SkBitmap* bm) {
3283 SkRasterHandleAllocator::Rec rec;
3284 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3285 return nullptr;
3286 }
3287 return rec.fHandle;
3288}
3289
3290std::unique_ptr<SkCanvas>
3291SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3292 const SkImageInfo& info, const Rec* rec) {
3293 if (!alloc || !supported_for_raster_canvas(info)) {
3294 return nullptr;
3295 }
3296
3297 SkBitmap bm;
3298 Handle hndl;
3299
3300 if (rec) {
3301 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3302 } else {
3303 hndl = alloc->allocBitmap(info, &bm);
3304 }
3305 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3306}