blob: 6ce38eaaad9b30fc363b5ea9b9a6f3c604ca5a01 [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"
Brian Osman3b655982017-03-07 16:58:08 -050048#include "SkGr.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)
Mike Reed566e53c2017-03-10 10:49:45 -050060 {
61 SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
62 }
Mike Reed139e5e02017-03-08 11:29:33 -050063
64 void resetForNextPicture(const SkIRect& bounds) {
Mike Reed566e53c2017-03-10 10:49:45 -050065 SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050066 this->privateResize(bounds.width(), bounds.height());
67 }
68
69protected:
70 // We don't track the clip at all (for performance), but we have to respond to some queries.
71 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
72 void onSave() override {}
73 void onRestore() override {}
74 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
75 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
76 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
77 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
78 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
79 bool onClipIsAA() const override { return false; }
80 void onAsRgnClip(SkRegion* rgn) const override {
81 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
82 }
83 ClipType onGetClipType() const override {
84 return kRect_ClipType;
85 }
86
87 void drawPaint(const SkPaint& paint) override {}
88 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
89 void drawRect(const SkRect&, const SkPaint&) override {}
90 void drawOval(const SkRect&, const SkPaint&) override {}
91 void drawRRect(const SkRRect&, const SkPaint&) override {}
92 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
93 void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {}
94 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
95 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
96 SkCanvas::SrcRectConstraint) override {}
97 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
98 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
99 const SkPaint&) override {}
100 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
101 void drawVertices(SkCanvas::VertexMode, int, const SkPoint[], const SkPoint[], const SkColor[],
102 SkBlendMode, const uint16_t[], int, const SkPaint&) override {}
103
104private:
105 typedef SkBaseDevice INHERITED;
106};
107
108///////////////////////////////////////////////////////////////////////////////////////////////////
109
reedc83a2972015-07-16 07:40:45 -0700110/*
111 * Return true if the drawing this rect would hit every pixels in the canvas.
112 *
113 * Returns false if
114 * - rect does not contain the canvas' bounds
115 * - paint is not fill
116 * - paint would blur or otherwise change the coverage of the rect
117 */
118bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
119 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700120 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
121 (int)kNone_ShaderOverrideOpacity,
122 "need_matching_enums0");
123 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
124 (int)kOpaque_ShaderOverrideOpacity,
125 "need_matching_enums1");
126 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
127 (int)kNotOpaque_ShaderOverrideOpacity,
128 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700129
130 const SkISize size = this->getBaseLayerSize();
131 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500132
133 // if we're clipped at all, we can't overwrite the entire surface
134 {
135 SkBaseDevice* base = this->getDevice();
136 SkBaseDevice* top = this->getTopDevice();
137 if (base != top) {
138 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
139 }
140 if (!base->clipIsWideOpen()) {
141 return false;
142 }
reedc83a2972015-07-16 07:40:45 -0700143 }
144
145 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700146 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700147 return false; // conservative
148 }
halcanaryc5769b22016-08-10 07:13:21 -0700149
150 SkRect devRect;
151 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
152 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700153 return false;
154 }
155 }
156
157 if (paint) {
158 SkPaint::Style paintStyle = paint->getStyle();
159 if (!(paintStyle == SkPaint::kFill_Style ||
160 paintStyle == SkPaint::kStrokeAndFill_Style)) {
161 return false;
162 }
163 if (paint->getMaskFilter() || paint->getLooper()
164 || paint->getPathEffect() || paint->getImageFilter()) {
165 return false; // conservative
166 }
167 }
168 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
169}
170
171///////////////////////////////////////////////////////////////////////////////////////////////////
172
reedd990e2f2014-12-22 11:58:30 -0800173static bool gIgnoreSaveLayerBounds;
174void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
175 gIgnoreSaveLayerBounds = ignore;
176}
177bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
178 return gIgnoreSaveLayerBounds;
179}
180
reed0acf1b42014-12-22 16:12:38 -0800181static bool gTreatSpriteAsBitmap;
182void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
183 gTreatSpriteAsBitmap = spriteAsBitmap;
184}
185bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
186 return gTreatSpriteAsBitmap;
187}
188
reed@google.comda17f752012-08-16 18:27:05 +0000189// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190//#define SK_TRACE_SAVERESTORE
191
192#ifdef SK_TRACE_SAVERESTORE
193 static int gLayerCounter;
194 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
195 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
196
197 static int gRecCounter;
198 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
199 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
200
201 static int gCanvasCounter;
202 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
203 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
204#else
205 #define inc_layer()
206 #define dec_layer()
207 #define inc_rec()
208 #define dec_rec()
209 #define inc_canvas()
210 #define dec_canvas()
211#endif
212
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000213typedef SkTLazy<SkPaint> SkLazyPaint;
214
reedc83a2972015-07-16 07:40:45 -0700215void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000216 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700217 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
218 ? SkSurface::kDiscard_ContentChangeMode
219 : SkSurface::kRetain_ContentChangeMode);
220 }
221}
222
223void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
224 ShaderOverrideOpacity overrideOpacity) {
225 if (fSurfaceBase) {
226 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
227 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
228 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
229 // and therefore we don't care which mode we're in.
230 //
231 if (fSurfaceBase->outstandingImageSnapshot()) {
232 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
233 mode = SkSurface::kDiscard_ContentChangeMode;
234 }
235 }
236 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000237 }
238}
239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000242/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 The clip/matrix/proc are fields that reflect the top of the save/restore
244 stack. Whenever the canvas changes, it marks a dirty flag, and then before
245 these are used (assuming we're not on a layer) we rebuild these cache
246 values: they reflect the top of the save stack, but translated and clipped
247 by the device's XY offset and bitmap-bounds.
248*/
249struct DeviceCM {
250 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000251 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000252 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000253 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700254 const SkMatrix* fMatrix;
255 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700256 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257
Mike Reeda1361362017-03-07 09:37:29 -0500258 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700259 : fNext(nullptr)
reed8c30a812016-04-20 16:36:51 -0700260 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700261 {
reed2c9e2002016-07-25 08:05:22 -0700262 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000263 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700264 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000265 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000267 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700268 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700269 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000270 }
reed@google.com4b226022011-01-11 18:32:13 +0000271
mtkleinfeaadee2015-04-08 11:25:48 -0700272 void reset(const SkIRect& bounds) {
273 SkASSERT(!fPaint);
274 SkASSERT(!fNext);
275 SkASSERT(fDevice);
276 fClip.setRect(bounds);
277 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278};
279
280/* This is the record we keep for each save/restore level in the stack.
281 Since a level optionally copies the matrix and/or stack, we have pointers
282 for these fields. If the value is copied for this level, the copy is
283 stored in the ...Storage field, and the pointer points to that. If the
284 value is not copied for this level, we ignore ...Storage, and just point
285 at the corresponding value in the previous level in the stack.
286*/
287class SkCanvas::MCRec {
288public:
reed1f836ee2014-07-07 07:49:34 -0700289 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700290 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291 /* If there are any layers in the stack, this points to the top-most
292 one that is at or below this level in the stack (so we know what
293 bitmap/device to draw into from this level. This value is NOT
294 reference counted, since the real owner is either our fLayer field,
295 or a previous one in a lower level.)
296 */
Mike Reeda1361362017-03-07 09:37:29 -0500297 DeviceCM* fTopLayer;
298 SkConservativeClip fRasterClip;
299 SkMatrix fMatrix;
300 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301
vjiaoblacke5de1302016-07-13 14:05:28 -0700302 // This is the current cumulative depth (aggregate of all done translateZ calls)
303 SkScalar fCurDrawDepth;
304
Mike Reeda1361362017-03-07 09:37:29 -0500305 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700306 fFilter = nullptr;
307 fLayer = nullptr;
308 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800309 fMatrix.reset();
310 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700311 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700312
reedd9544982014-09-09 18:46:22 -0700313 // don't bother initializing fNext
314 inc_rec();
315 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700316 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
317 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700318 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700319 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700320 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800321 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700322
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323 // don't bother initializing fNext
324 inc_rec();
325 }
326 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000327 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700328 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 dec_rec();
330 }
mtkleinfeaadee2015-04-08 11:25:48 -0700331
332 void reset(const SkIRect& bounds) {
333 SkASSERT(fLayer);
334 SkASSERT(fDeferredSaveCount == 0);
335
336 fMatrix.reset();
337 fRasterClip.setRect(bounds);
338 fLayer->reset(bounds);
339 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340};
341
Mike Reeda1361362017-03-07 09:37:29 -0500342class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343public:
Mike Reeda1361362017-03-07 09:37:29 -0500344 SkDrawIter(SkCanvas* canvas)
345 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
346 {}
reed@google.com4b226022011-01-11 18:32:13 +0000347
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000349 const DeviceCM* rec = fCurrLayer;
350 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 fDevice = rec->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 fPaint = rec->fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700354 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 return true;
356 }
357 return false;
358 }
reed@google.com4b226022011-01-11 18:32:13 +0000359
reed@google.com6f8f2922011-03-04 22:27:10 +0000360 int getX() const { return fDevice->getOrigin().x(); }
361 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000363
Mike Reed99330ba2017-02-22 11:01:08 -0500364 SkBaseDevice* fDevice;
365
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 const DeviceCM* fCurrLayer;
368 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369};
370
Mike Reed7627fa52017-02-08 10:07:53 -0500371#define FOR_EACH_TOP_DEVICE( code ) \
372 do { \
373 DeviceCM* layer = fMCRec->fTopLayer; \
374 while (layer) { \
375 SkBaseDevice* device = layer->fDevice; \
Mike Reedc42a1cd2017-02-14 14:25:14 -0500376 if (device) { \
377 code; \
378 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500379 layer = layer->fNext; \
380 } \
381 } while (0)
382
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383/////////////////////////////////////////////////////////////////////////////
384
reeddbc3cef2015-04-29 12:18:57 -0700385static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
386 return lazy->isValid() ? lazy->get() : lazy->set(orig);
387}
388
389/**
390 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700391 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700392 */
reedd053ce92016-03-22 10:17:23 -0700393static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700394 SkImageFilter* imgf = paint.getImageFilter();
395 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700396 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700397 }
398
reedd053ce92016-03-22 10:17:23 -0700399 SkColorFilter* imgCFPtr;
400 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700401 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700402 }
reedd053ce92016-03-22 10:17:23 -0700403 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700404
405 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700406 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700407 // there is no existing paint colorfilter, so we can just return the imagefilter's
408 return imgCF;
409 }
410
411 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
412 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700413 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700414}
415
senorblanco87e066e2015-10-28 11:23:36 -0700416/**
417 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
418 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
419 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
420 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
421 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
422 * conservative "effective" bounds based on the settings in the paint... with one exception. This
423 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
424 * deliberately ignored.
425 */
426static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
427 const SkRect& rawBounds,
428 SkRect* storage) {
429 SkPaint tmpUnfiltered(paint);
430 tmpUnfiltered.setImageFilter(nullptr);
431 if (tmpUnfiltered.canComputeFastBounds()) {
432 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
433 } else {
434 return rawBounds;
435 }
436}
437
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438class AutoDrawLooper {
439public:
senorblanco87e066e2015-10-28 11:23:36 -0700440 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
441 // paint. It's used to determine the size of the offscreen layer for filters.
442 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700443 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700444 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000445 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800446#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800448#else
449 fFilter = nullptr;
450#endif
reed4a8126e2014-09-22 07:29:03 -0700451 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000452 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700453 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000454 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000455
reedd053ce92016-03-22 10:17:23 -0700456 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700457 if (simplifiedCF) {
458 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700459 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700460 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700461 fPaint = paint;
462 }
463
464 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700465 /**
466 * We implement ImageFilters for a given draw by creating a layer, then applying the
467 * imagefilter to the pixels of that layer (its backing surface/image), and then
468 * we call restore() to xfer that layer to the main canvas.
469 *
470 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
471 * 2. Generate the src pixels:
472 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
473 * return (fPaint). We then draw the primitive (using srcover) into a cleared
474 * buffer/surface.
475 * 3. Restore the layer created in #1
476 * The imagefilter is passed the buffer/surface from the layer (now filled with the
477 * src pixels of the primitive). It returns a new "filtered" buffer, which we
478 * draw onto the previous layer using the xfermode from the original paint.
479 */
reed@google.com8926b162012-03-23 15:36:36 +0000480 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500481 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700482 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700483 SkRect storage;
484 if (rawBounds) {
485 // Make rawBounds include all paint outsets except for those due to image filters.
486 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
487 }
reedbfd5f172016-01-07 11:28:08 -0800488 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700489 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700490 fTempLayerForImageFilter = true;
491 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000492 }
493
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000494 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500495 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000496 fIsSimple = false;
497 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700498 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000499 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700500 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000501 }
502 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000503
reed@android.com8a1c16f2008-12-17 15:59:43 +0000504 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700505 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000506 fCanvas->internalRestore();
507 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000508 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000510
reed@google.com4e2b3d32011-04-07 14:18:59 +0000511 const SkPaint& paint() const {
512 SkASSERT(fPaint);
513 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@google.com129ec222012-05-15 13:24:09 +0000516 bool next(SkDrawFilter::Type drawType) {
517 if (fDone) {
518 return false;
519 } else if (fIsSimple) {
520 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000521 return !fPaint->nothingToDraw();
522 } else {
523 return this->doNext(drawType);
524 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000525 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000526
reed@android.com8a1c16f2008-12-17 15:59:43 +0000527private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500528 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700529 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000530 SkCanvas* fCanvas;
531 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000532 SkDrawFilter* fFilter;
533 const SkPaint* fPaint;
534 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700535 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000536 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000537 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000538 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500539 char fStorage[48];
540 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000541
542 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000543};
544
reed@google.com129ec222012-05-15 13:24:09 +0000545bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700546 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000547 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700548 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000549
reeddbc3cef2015-04-29 12:18:57 -0700550 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
551 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000552
reed5c476fb2015-04-20 08:04:21 -0700553 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700554 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700555 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000556 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000557
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000558 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000559 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000560 return false;
561 }
562 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000563 if (!fFilter->filter(paint, drawType)) {
564 fDone = true;
565 return false;
566 }
halcanary96fcdcc2015-08-27 07:41:13 -0700567 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000568 // no looper means we only draw once
569 fDone = true;
570 }
571 }
572 fPaint = paint;
573
574 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000575 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000576 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000577 }
578
579 // call this after any possible paint modifiers
580 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700581 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000582 return false;
583 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000584 return true;
585}
586
reed@android.com8a1c16f2008-12-17 15:59:43 +0000587////////// macros to place around the internal draw calls //////////////////
588
reed3aafe112016-08-18 12:45:34 -0700589#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
590 this->predrawNotify(); \
591 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
592 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800593 SkDrawIter iter(this);
594
595
reed@google.com8926b162012-03-23 15:36:36 +0000596#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000597 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700598 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000599 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000600 SkDrawIter iter(this);
601
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000602#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000603 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700604 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000605 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000607
reedc83a2972015-07-16 07:40:45 -0700608#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
609 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700610 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700611 while (looper.next(type)) { \
612 SkDrawIter iter(this);
613
reed@google.com4e2b3d32011-04-07 14:18:59 +0000614#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615
616////////////////////////////////////////////////////////////////////////////
617
msarettfbfa2582016-08-12 08:29:08 -0700618static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
619 if (bounds.isEmpty()) {
620 return SkRect::MakeEmpty();
621 }
622
623 // Expand bounds out by 1 in case we are anti-aliasing. We store the
624 // bounds as floats to enable a faster quick reject implementation.
625 SkRect dst;
626 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
627 return dst;
628}
629
mtkleinfeaadee2015-04-08 11:25:48 -0700630void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
631 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700632 fMCRec->reset(bounds);
633
634 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500635 // know that the device is a SkNoPixelsDevice.
636 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice)->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700637 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700638 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700639}
640
reedd9544982014-09-09 18:46:22 -0700641SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800642 if (device && device->forceConservativeRasterClip()) {
643 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
644 }
reed42b73eb2015-11-20 13:42:42 -0800645
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000646 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800647 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700648 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700649#ifdef SK_EXPERIMENTAL_SHADOWING
650 fLights = nullptr;
651#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000652
653 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500654 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500655 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700656 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657
reeda499f902015-05-01 09:34:31 -0700658 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
659 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Mike Reeda1361362017-03-07 09:37:29 -0500660 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700661
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663
halcanary96fcdcc2015-08-27 07:41:13 -0700664 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000665
reedf92c8662014-08-18 08:02:43 -0700666 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700667 // The root device and the canvas should always have the same pixel geometry
668 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700669 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800670 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700671 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500672
Mike Reedc42a1cd2017-02-14 14:25:14 -0500673 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700674 }
msarettfbfa2582016-08-12 08:29:08 -0700675
reedf92c8662014-08-18 08:02:43 -0700676 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677}
678
reed@google.comcde92112011-07-06 20:00:52 +0000679SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000680 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700681 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000682{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000683 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000684
halcanary96fcdcc2015-08-27 07:41:13 -0700685 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000686}
687
reed96a857e2015-01-25 10:33:58 -0800688SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000689 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800690 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000691{
692 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700693
Mike Reed566e53c2017-03-10 10:49:45 -0500694 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700695 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700696}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000697
reed78e27682014-11-19 08:04:34 -0800698SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700699 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700700 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700701{
702 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700703
Mike Reed566e53c2017-03-10 10:49:45 -0500704 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
705 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700706}
707
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000708SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000709 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700710 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000711{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700713
reedd9544982014-09-09 18:46:22 -0700714 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715}
716
robertphillipsfcf78292015-06-19 11:49:52 -0700717SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
718 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700719 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700720{
721 inc_canvas();
722
723 this->init(device, flags);
724}
725
reed4a8126e2014-09-22 07:29:03 -0700726SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700727 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700728 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700729{
730 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700731
Hal Canary704cd322016-11-07 14:13:52 -0500732 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
733 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700734}
reed29c857d2014-09-21 10:25:07 -0700735
Mike Reed356f7c22017-01-10 11:58:39 -0500736SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
737 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700738 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
739 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500740 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700741{
742 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700743
Mike Reed356f7c22017-01-10 11:58:39 -0500744 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500745 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746}
747
Mike Reed356f7c22017-01-10 11:58:39 -0500748SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
749
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750SkCanvas::~SkCanvas() {
751 // free up the contents of our deque
752 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000753
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754 this->internalRestore(); // restore the last, since we're going away
755
halcanary385fe4d2015-08-26 13:07:48 -0700756 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000757
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758 dec_canvas();
759}
760
fmalita53d9f1c2016-01-25 06:23:54 -0800761#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762SkDrawFilter* SkCanvas::getDrawFilter() const {
763 return fMCRec->fFilter;
764}
765
766SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700767 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
769 return filter;
770}
fmalita77650002016-01-21 18:47:11 -0800771#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000773SkMetaData& SkCanvas::getMetaData() {
774 // metadata users are rare, so we lazily allocate it. If that changes we
775 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700776 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000777 fMetaData = new SkMetaData;
778 }
779 return *fMetaData;
780}
781
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782///////////////////////////////////////////////////////////////////////////////
783
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000784void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700785 this->onFlush();
786}
787
788void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000789 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000790 if (device) {
791 device->flush();
792 }
793}
794
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000795SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000796 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000797 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
798}
799
senorblancoafc7cce2016-02-02 18:44:15 -0800800SkIRect SkCanvas::getTopLayerBounds() const {
801 SkBaseDevice* d = this->getTopDevice();
802 if (!d) {
803 return SkIRect::MakeEmpty();
804 }
805 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
806}
807
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000808SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000810 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000811 SkASSERT(rec && rec->fLayer);
812 return rec->fLayer->fDevice;
813}
814
Florin Malita0ed3b642017-01-13 16:56:38 +0000815SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000816 return fMCRec->fTopLayer->fDevice;
817}
818
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000819bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000820 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700821 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700822 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000823 return false;
824 }
825 weAllocated = true;
826 }
827
reedcf01e312015-05-23 19:14:51 -0700828 SkAutoPixmapUnlock unlocker;
829 if (bitmap->requestLock(&unlocker)) {
830 const SkPixmap& pm = unlocker.pixmap();
831 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
832 return true;
833 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000834 }
835
836 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500837 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000838 }
839 return false;
840}
reed@google.com51df9e32010-12-23 19:29:18 +0000841
bsalomon@google.comc6980972011-11-02 19:57:21 +0000842bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000843 SkIRect r = srcRect;
844 const SkISize size = this->getBaseLayerSize();
845 if (!r.intersect(0, 0, size.width(), size.height())) {
846 bitmap->reset();
847 return false;
848 }
849
reed84825042014-09-02 12:50:45 -0700850 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000851 // bitmap will already be reset.
852 return false;
853 }
854 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
855 bitmap->reset();
856 return false;
857 }
858 return true;
859}
860
reed96472de2014-12-10 09:53:42 -0800861bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000862 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000863 if (!device) {
864 return false;
865 }
mtkleinf0f14112014-12-12 08:46:25 -0800866
Matt Sarett03dd6d52017-01-23 12:15:09 -0500867 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000868}
869
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000870bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700871 SkAutoPixmapUnlock unlocker;
872 if (bitmap.requestLock(&unlocker)) {
873 const SkPixmap& pm = unlocker.pixmap();
874 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000875 }
876 return false;
877}
878
Matt Sarett03dd6d52017-01-23 12:15:09 -0500879bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000880 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000881 SkBaseDevice* device = this->getDevice();
882 if (!device) {
883 return false;
884 }
885
Matt Sarett03dd6d52017-01-23 12:15:09 -0500886 // This check gives us an early out and prevents generation ID churn on the surface.
887 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
888 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
889 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
890 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000891 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000892
Matt Sarett03dd6d52017-01-23 12:15:09 -0500893 // Tell our owning surface to bump its generation ID.
894 const bool completeOverwrite =
895 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700896 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700897
Matt Sarett03dd6d52017-01-23 12:15:09 -0500898 // This can still fail, most notably in the case of a invalid color type or alpha type
899 // conversion. We could pull those checks into this function and avoid the unnecessary
900 // generation ID bump. But then we would be performing those checks twice, since they
901 // are also necessary at the bitmap/pixmap entry points.
902 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000903}
reed@google.com51df9e32010-12-23 19:29:18 +0000904
reed@android.com8a1c16f2008-12-17 15:59:43 +0000905//////////////////////////////////////////////////////////////////////////////
906
reed2ff1fce2014-12-11 07:07:37 -0800907void SkCanvas::checkForDeferredSave() {
908 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800909 this->doSave();
910 }
911}
912
reedf0090cb2014-11-26 08:55:51 -0800913int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800914#ifdef SK_DEBUG
915 int count = 0;
916 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
917 for (;;) {
918 const MCRec* rec = (const MCRec*)iter.next();
919 if (!rec) {
920 break;
921 }
922 count += 1 + rec->fDeferredSaveCount;
923 }
924 SkASSERT(count == fSaveCount);
925#endif
926 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800927}
928
929int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800930 fSaveCount += 1;
931 fMCRec->fDeferredSaveCount += 1;
932 return this->getSaveCount() - 1; // return our prev value
933}
934
935void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800936 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700937
938 SkASSERT(fMCRec->fDeferredSaveCount > 0);
939 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800940 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800941}
942
943void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800944 if (fMCRec->fDeferredSaveCount > 0) {
945 SkASSERT(fSaveCount > 1);
946 fSaveCount -= 1;
947 fMCRec->fDeferredSaveCount -= 1;
948 } else {
949 // check for underflow
950 if (fMCStack.count() > 1) {
951 this->willRestore();
952 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700953 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800954 this->internalRestore();
955 this->didRestore();
956 }
reedf0090cb2014-11-26 08:55:51 -0800957 }
958}
959
960void SkCanvas::restoreToCount(int count) {
961 // sanity check
962 if (count < 1) {
963 count = 1;
964 }
mtkleinf0f14112014-12-12 08:46:25 -0800965
reedf0090cb2014-11-26 08:55:51 -0800966 int n = this->getSaveCount() - count;
967 for (int i = 0; i < n; ++i) {
968 this->restore();
969 }
970}
971
reed2ff1fce2014-12-11 07:07:37 -0800972void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700974 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000975 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000976
Mike Reedc42a1cd2017-02-14 14:25:14 -0500977 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978}
979
reed4960eee2015-12-18 07:09:18 -0800980bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800981 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982}
983
reed4960eee2015-12-18 07:09:18 -0800984bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700985 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500986 SkIRect clipBounds = this->getDeviceClipBounds();
987 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000988 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000989 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000990
reed96e657d2015-03-10 17:30:07 -0700991 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
992
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000993 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700994 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800995 if (bounds && !imageFilter->canComputeFastBounds()) {
996 bounds = nullptr;
997 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000998 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000999 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001000 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001001 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001002
reed96e657d2015-03-10 17:30:07 -07001003 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004 r.roundOut(&ir);
1005 // early exit if the layer's bounds are clipped out
1006 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001007 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -05001008 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -07001009 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001010 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001011 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001012 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001013 }
1014 } else { // no user bounds, so just use the clip
1015 ir = clipBounds;
1016 }
reed180aec42015-03-11 10:39:04 -07001017 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001018
reed4960eee2015-12-18 07:09:18 -08001019 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001020 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -07001021 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001022 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001023 }
1024
1025 if (intersection) {
1026 *intersection = ir;
1027 }
1028 return true;
1029}
1030
reed4960eee2015-12-18 07:09:18 -08001031
reed4960eee2015-12-18 07:09:18 -08001032int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1033 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001034}
1035
reed70ee31b2015-12-10 13:44:45 -08001036int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001037 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1038}
1039
1040int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1041 SaveLayerRec rec(origRec);
1042 if (gIgnoreSaveLayerBounds) {
1043 rec.fBounds = nullptr;
1044 }
1045 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1046 fSaveCount += 1;
1047 this->internalSaveLayer(rec, strategy);
1048 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001049}
1050
reeda2217ef2016-07-20 06:04:34 -07001051void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001052 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001053 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001054 SkDraw draw;
1055 SkRasterClip rc;
1056 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1057 if (!dst->accessPixels(&draw.fDst)) {
1058 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001059 }
reeda2217ef2016-07-20 06:04:34 -07001060 draw.fMatrix = &SkMatrix::I();
1061 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001062
1063 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001064 if (filter) {
1065 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1066 }
reeda2217ef2016-07-20 06:04:34 -07001067
Mike Reedc42a1cd2017-02-14 14:25:14 -05001068 int x = src->getOrigin().x() - dstOrigin.x();
1069 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001070 auto special = src->snapSpecial();
1071 if (special) {
Mike Reeda1361362017-03-07 09:37:29 -05001072 dst->drawSpecial(special.get(), x, y, p);
reeda2217ef2016-07-20 06:04:34 -07001073 }
robertphillips7354a4b2015-12-16 05:08:27 -08001074}
reed70ee31b2015-12-10 13:44:45 -08001075
reed129ed1c2016-02-22 06:42:31 -08001076static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1077 const SkPaint* paint) {
1078 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1079 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001080 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001081 const bool hasImageFilter = paint && paint->getImageFilter();
1082
1083 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1084 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1085 // force to L32
1086 return SkImageInfo::MakeN32(w, h, alphaType);
1087 } else {
1088 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001089 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001090 }
1091}
1092
reed4960eee2015-12-18 07:09:18 -08001093void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1094 const SkRect* bounds = rec.fBounds;
1095 const SkPaint* paint = rec.fPaint;
1096 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1097
reed8c30a812016-04-20 16:36:51 -07001098 SkLazyPaint lazyP;
1099 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1100 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001101 SkMatrix remainder;
1102 SkSize scale;
1103 /*
1104 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1105 * but they do handle scaling. To accommodate this, we do the following:
1106 *
1107 * 1. Stash off the current CTM
1108 * 2. Decompose the CTM into SCALE and REMAINDER
1109 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1110 * contains the REMAINDER
1111 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1112 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1113 * of the original imagefilter, and draw that (via drawSprite)
1114 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1115 *
1116 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1117 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1118 */
reed96a04f32016-04-25 09:25:15 -07001119 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001120 stashedMatrix.decomposeScale(&scale, &remainder))
1121 {
1122 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1123 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1124 SkPaint* p = lazyP.set(*paint);
1125 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1126 SkFilterQuality::kLow_SkFilterQuality,
1127 sk_ref_sp(imageFilter)));
1128 imageFilter = p->getImageFilter();
1129 paint = p;
1130 }
reed8c30a812016-04-20 16:36:51 -07001131
junov@chromium.orga907ac32012-02-24 21:54:07 +00001132 // do this before we create the layer. We don't call the public save() since
1133 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001134 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001135
junov@chromium.orga907ac32012-02-24 21:54:07 +00001136 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001137 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001138 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001139 }
1140
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001141 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1142 // the clipRectBounds() call above?
1143 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001144 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001145 }
1146
reed4960eee2015-12-18 07:09:18 -08001147 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001148 SkPixelGeometry geo = fProps.pixelGeometry();
1149 if (paint) {
reed76033be2015-03-14 10:54:31 -07001150 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001151 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001152 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001153 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001154 }
1155 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001156
robertphillips5139e502016-07-19 05:10:40 -07001157 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001158 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001159 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001160 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001161 }
reedb2db8982014-11-13 12:41:02 -08001162
robertphillips5139e502016-07-19 05:10:40 -07001163 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001164 paint);
1165
Hal Canary704cd322016-11-07 14:13:52 -05001166 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001167 {
reed70ee31b2015-12-10 13:44:45 -08001168 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001169 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001170 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001171 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001172 preserveLCDText,
1173 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001174 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1175 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001176 return;
reed61f501f2015-04-29 08:34:00 -07001177 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001178 }
Hal Canary704cd322016-11-07 14:13:52 -05001179 DeviceCM* layer =
Mike Reeda1361362017-03-07 09:37:29 -05001180 new DeviceCM(newDevice.get(), paint, this, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181
Mike Reedb43a3e02017-02-11 10:18:58 -05001182 // only have a "next" if this new layer doesn't affect the clip (rare)
1183 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184 fMCRec->fLayer = layer;
1185 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001186
Mike Reedc61abee2017-02-28 17:45:27 -05001187 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001188 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001189 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001190 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001191
Mike Reedc42a1cd2017-02-14 14:25:14 -05001192 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1193
1194 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1195 if (layer->fNext) {
1196 // need to punch a hole in the previous device, so we don't draw there, given that
1197 // the new top-layer will allow drawing to happen "below" it.
1198 SkRegion hole(ir);
1199 do {
1200 layer = layer->fNext;
1201 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1202 } while (layer->fNext);
1203 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204}
1205
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001206int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001207 if (0xFF == alpha) {
1208 return this->saveLayer(bounds, nullptr);
1209 } else {
1210 SkPaint tmpPaint;
1211 tmpPaint.setAlpha(alpha);
1212 return this->saveLayer(bounds, &tmpPaint);
1213 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001214}
1215
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216void SkCanvas::internalRestore() {
1217 SkASSERT(fMCStack.count() != 0);
1218
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001219 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220 DeviceCM* layer = fMCRec->fLayer; // may be null
1221 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001222 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223
1224 // now do the normal restore()
1225 fMCRec->~MCRec(); // balanced in save()
1226 fMCStack.pop_back();
1227 fMCRec = (MCRec*)fMCStack.back();
1228
Mike Reedc42a1cd2017-02-14 14:25:14 -05001229 if (fMCRec) {
1230 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1231 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001232
reed@android.com8a1c16f2008-12-17 15:59:43 +00001233 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1234 since if we're being recorded, we don't want to record this (the
1235 recorder will have already recorded the restore).
1236 */
bsalomon49f085d2014-09-05 13:34:00 -07001237 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001238 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001239 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001240 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001241 // restore what we smashed in internalSaveLayer
1242 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001243 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001244 delete layer;
reedb679ca82015-04-07 04:40:48 -07001245 } else {
1246 // we're at the root
reeda499f902015-05-01 09:34:31 -07001247 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001248 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001249 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001250 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001251 }
msarettfbfa2582016-08-12 08:29:08 -07001252
1253 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001254 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001255 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1256 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001257}
1258
reede8f30622016-03-23 18:59:25 -07001259sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001260 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001261 props = &fProps;
1262 }
1263 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001264}
1265
reede8f30622016-03-23 18:59:25 -07001266sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001267 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001268 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001269}
1270
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001271SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001272 return this->onImageInfo();
1273}
1274
1275SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001276 SkBaseDevice* dev = this->getDevice();
1277 if (dev) {
1278 return dev->imageInfo();
1279 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001280 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001281 }
1282}
1283
brianosman898235c2016-04-06 07:38:23 -07001284bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001285 return this->onGetProps(props);
1286}
1287
1288bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001289 SkBaseDevice* dev = this->getDevice();
1290 if (dev) {
1291 if (props) {
1292 *props = fProps;
1293 }
1294 return true;
1295 } else {
1296 return false;
1297 }
1298}
1299
reed6ceeebd2016-03-09 14:26:26 -08001300bool SkCanvas::peekPixels(SkPixmap* pmap) {
1301 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001302}
1303
reed884e97c2015-05-26 11:31:54 -07001304bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001305 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001306 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001307}
1308
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001309void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001310 SkPixmap pmap;
1311 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001312 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001313 }
1314 if (info) {
1315 *info = pmap.info();
1316 }
1317 if (rowBytes) {
1318 *rowBytes = pmap.rowBytes();
1319 }
1320 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001321 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001322 }
reed884e97c2015-05-26 11:31:54 -07001323 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001324}
1325
reed884e97c2015-05-26 11:31:54 -07001326bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001327 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001328 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001329}
1330
reed@android.com8a1c16f2008-12-17 15:59:43 +00001331/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332
reed7503d602016-07-15 14:23:29 -07001333void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001335 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001336 paint = &tmp;
1337 }
reed@google.com4b226022011-01-11 18:32:13 +00001338
reed@google.com8926b162012-03-23 15:36:36 +00001339 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001340
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001342 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001343 paint = &looper.paint();
1344 SkImageFilter* filter = paint->getImageFilter();
1345 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001346 if (filter) {
1347 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1348 if (specialImage) {
Mike Reeda1361362017-03-07 09:37:29 -05001349 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint);
Robert Phillips833dcf42016-11-18 08:44:13 -05001350 }
reed@google.com76dd2772012-01-05 21:15:07 +00001351 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001352 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001353 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354 }
reeda2217ef2016-07-20 06:04:34 -07001355
reed@google.com4e2b3d32011-04-07 14:18:59 +00001356 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001357}
1358
reed32704672015-12-16 08:27:10 -08001359/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001360
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001361void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001362 if (dx || dy) {
1363 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001364 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001365
reedfe69b502016-09-12 06:31:48 -07001366 // Translate shouldn't affect the is-scale-translateness of the matrix.
1367 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001368
Mike Reedc42a1cd2017-02-14 14:25:14 -05001369 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001370
reedfe69b502016-09-12 06:31:48 -07001371 this->didTranslate(dx,dy);
1372 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001373}
1374
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001375void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001376 SkMatrix m;
1377 m.setScale(sx, sy);
1378 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379}
1380
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001381void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001382 SkMatrix m;
1383 m.setRotate(degrees);
1384 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385}
1386
bungeman7438bfc2016-07-12 15:01:19 -07001387void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1388 SkMatrix m;
1389 m.setRotate(degrees, px, py);
1390 this->concat(m);
1391}
1392
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001393void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001394 SkMatrix m;
1395 m.setSkew(sx, sy);
1396 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001397}
1398
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001399void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001400 if (matrix.isIdentity()) {
1401 return;
1402 }
1403
reed2ff1fce2014-12-11 07:07:37 -08001404 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001405 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001406 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001407
Mike Reed7627fa52017-02-08 10:07:53 -05001408 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001409
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001410 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001411}
1412
reed8c30a812016-04-20 16:36:51 -07001413void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001414 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001415 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001416
Mike Reedc42a1cd2017-02-14 14:25:14 -05001417 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001418}
1419
1420void SkCanvas::setMatrix(const SkMatrix& matrix) {
1421 this->checkForDeferredSave();
1422 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001423 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424}
1425
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001427 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428}
1429
vjiaoblack95302da2016-07-21 10:25:54 -07001430#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001431void SkCanvas::translateZ(SkScalar z) {
1432 this->checkForDeferredSave();
1433 this->fMCRec->fCurDrawDepth += z;
1434 this->didTranslateZ(z);
1435}
1436
1437SkScalar SkCanvas::getZ() const {
1438 return this->fMCRec->fCurDrawDepth;
1439}
1440
vjiaoblack95302da2016-07-21 10:25:54 -07001441void SkCanvas::setLights(sk_sp<SkLights> lights) {
1442 this->fLights = lights;
1443}
1444
1445sk_sp<SkLights> SkCanvas::getLights() const {
1446 return this->fLights;
1447}
1448#endif
1449
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450//////////////////////////////////////////////////////////////////////////////
1451
Mike Reedc1f77742016-12-09 09:00:50 -05001452void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001453 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001454 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1455 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001456}
1457
Mike Reedc1f77742016-12-09 09:00:50 -05001458void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001459 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001460
Mike Reed7627fa52017-02-08 10:07:53 -05001461 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001462
reedc64eff52015-11-21 12:39:45 -08001463 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001464 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1465 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001466 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001467}
1468
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001469void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1470 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001471 if (fClipRestrictionRect.isEmpty()) {
1472 // we notify the device, but we *dont* resolve deferred saves (since we're just
1473 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001474 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001475 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001476 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001477 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001478 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001479 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001480 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1481 }
1482}
1483
Mike Reedc1f77742016-12-09 09:00:50 -05001484void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001485 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001486 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001487 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001488 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1489 } else {
1490 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001491 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001492}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001493
Mike Reedc1f77742016-12-09 09:00:50 -05001494void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001495 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001496
Brian Salomona3b45d42016-10-03 11:36:16 -04001497 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001498
Mike Reed7627fa52017-02-08 10:07:53 -05001499 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001500
Brian Salomona3b45d42016-10-03 11:36:16 -04001501 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1502 isAA);
1503 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001504}
1505
Mike Reedc1f77742016-12-09 09:00:50 -05001506void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001507 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001508 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001509
1510 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1511 SkRect r;
1512 if (path.isRect(&r)) {
1513 this->onClipRect(r, op, edgeStyle);
1514 return;
1515 }
1516 SkRRect rrect;
1517 if (path.isOval(&r)) {
1518 rrect.setOval(r);
1519 this->onClipRRect(rrect, op, edgeStyle);
1520 return;
1521 }
1522 if (path.isRRect(&rrect)) {
1523 this->onClipRRect(rrect, op, edgeStyle);
1524 return;
1525 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001526 }
robertphillips39f05382015-11-24 09:30:12 -08001527
1528 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001529}
1530
Mike Reedc1f77742016-12-09 09:00:50 -05001531void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001532 AutoValidateClip avc(this);
1533
Brian Salomona3b45d42016-10-03 11:36:16 -04001534 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001535
Mike Reed7627fa52017-02-08 10:07:53 -05001536 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001537
Brian Salomona3b45d42016-10-03 11:36:16 -04001538 const SkPath* rasterClipPath = &path;
1539 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001540 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1541 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001542 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001543}
1544
Mike Reedc1f77742016-12-09 09:00:50 -05001545void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001546 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001547 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001548}
1549
Mike Reedc1f77742016-12-09 09:00:50 -05001550void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001551 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001552
reed@google.com5c3d1472011-02-22 19:12:23 +00001553 AutoValidateClip avc(this);
1554
reed73603f32016-09-20 08:42:38 -07001555 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001556 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001557}
1558
reed@google.com819c9212011-02-23 18:56:55 +00001559#ifdef SK_DEBUG
1560void SkCanvas::validateClip() const {
1561 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001562 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001563 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001564 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001565 return;
1566 }
reed@google.com819c9212011-02-23 18:56:55 +00001567}
1568#endif
1569
Mike Reed8310f0e2017-03-08 21:42:37 +00001570void SkCanvas::replayClips(ClipVisitor* visitor) const {
1571#if 0
1572 SkClipStack::B2TIter iter(*fClipStack);
1573 const SkClipStack::Element* element;
1574
1575 while ((element = iter.next()) != nullptr) {
1576 element->replay(visitor);
1577 }
1578#endif
1579}
1580
Mike Reeda1361362017-03-07 09:37:29 -05001581bool SkCanvas::androidFramework_isClipAA() const {
1582 bool containsAA = false;
1583
1584 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1585
1586 return containsAA;
1587}
1588
1589class RgnAccumulator {
1590 SkRegion* fRgn;
1591public:
1592 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1593 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1594 SkIPoint origin = device->getOrigin();
1595 if (origin.x() | origin.y()) {
1596 rgn->translate(origin.x(), origin.y());
1597 }
1598 fRgn->op(*rgn, SkRegion::kUnion_Op);
1599 }
1600};
1601
1602void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1603 RgnAccumulator accum(rgn);
1604 SkRegion tmp;
1605
1606 rgn->setEmpty();
1607 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001608}
1609
reed@google.com5c3d1472011-02-22 19:12:23 +00001610///////////////////////////////////////////////////////////////////////////////
1611
reed@google.com754de5f2014-02-24 19:38:20 +00001612bool SkCanvas::isClipEmpty() const {
Mike Reeda1361362017-03-07 09:37:29 -05001613 SkBaseDevice* dev = this->getTopDevice();
1614 // if no device we return true
1615 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
reed@google.com754de5f2014-02-24 19:38:20 +00001616}
1617
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001618bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001619 SkBaseDevice* dev = this->getTopDevice();
1620 // if no device we return false
1621 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001622}
1623
msarettfbfa2582016-08-12 08:29:08 -07001624static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1625#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1626 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1627 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1628 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1629 return 0xF != _mm_movemask_ps(mask);
1630#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1631 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1632 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1633 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1634 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1635#else
1636 SkRect devRectAsRect;
1637 SkRect devClipAsRect;
1638 devRect.store(&devRectAsRect.fLeft);
1639 devClip.store(&devClipAsRect.fLeft);
1640 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1641#endif
1642}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001643
msarettfbfa2582016-08-12 08:29:08 -07001644// It's important for this function to not be inlined. Otherwise the compiler will share code
1645// between the fast path and the slow path, resulting in two slow paths.
1646static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1647 const SkMatrix& matrix) {
1648 SkRect deviceRect;
1649 matrix.mapRect(&deviceRect, src);
1650 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1651}
1652
1653bool SkCanvas::quickReject(const SkRect& src) const {
1654#ifdef SK_DEBUG
1655 // Verify that fDeviceClipBounds are set properly.
1656 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001657 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001658 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001659 } else {
msarettfbfa2582016-08-12 08:29:08 -07001660 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001661 }
msarettfbfa2582016-08-12 08:29:08 -07001662
msarett9637ea92016-08-18 14:03:30 -07001663 // Verify that fIsScaleTranslate is set properly.
1664 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001665#endif
1666
msarett9637ea92016-08-18 14:03:30 -07001667 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001668 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1669 }
1670
1671 // We inline the implementation of mapScaleTranslate() for the fast path.
1672 float sx = fMCRec->fMatrix.getScaleX();
1673 float sy = fMCRec->fMatrix.getScaleY();
1674 float tx = fMCRec->fMatrix.getTranslateX();
1675 float ty = fMCRec->fMatrix.getTranslateY();
1676 Sk4f scale(sx, sy, sx, sy);
1677 Sk4f trans(tx, ty, tx, ty);
1678
1679 // Apply matrix.
1680 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1681
1682 // Make sure left < right, top < bottom.
1683 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1684 Sk4f min = Sk4f::Min(ltrb, rblt);
1685 Sk4f max = Sk4f::Max(ltrb, rblt);
1686 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1687 // ARM this sequence generates the fastest (a single instruction).
1688 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1689
1690 // Check if the device rect is NaN or outside the clip.
1691 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692}
1693
reed@google.com3b3e8952012-08-16 20:53:31 +00001694bool SkCanvas::quickReject(const SkPath& path) const {
1695 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001696}
1697
Mike Reed42e8c532017-01-23 14:09:13 -05001698SkRect SkCanvas::onGetLocalClipBounds() const {
1699 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001700 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001701 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001702 }
1703
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001704 SkMatrix inverse;
1705 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001706 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001707 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001708 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001709
Mike Reed42e8c532017-01-23 14:09:13 -05001710 SkRect bounds;
1711 SkRect r;
1712 // adjust it outwards in case we are antialiasing
1713 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001714
Mike Reed42e8c532017-01-23 14:09:13 -05001715 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1716 ibounds.fRight + inset, ibounds.fBottom + inset);
1717 inverse.mapRect(&bounds, r);
1718 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001719}
1720
Mike Reed42e8c532017-01-23 14:09:13 -05001721SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001722 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001723}
1724
reed@android.com8a1c16f2008-12-17 15:59:43 +00001725const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001726 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001727}
1728
Brian Osman11052242016-10-27 14:47:55 -04001729GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001730 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001731 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001732}
1733
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001734GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001735 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001736 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001737}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001738
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001739void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1740 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001741 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001742 if (outer.isEmpty()) {
1743 return;
1744 }
1745 if (inner.isEmpty()) {
1746 this->drawRRect(outer, paint);
1747 return;
1748 }
1749
1750 // We don't have this method (yet), but technically this is what we should
1751 // be able to assert...
1752 // SkASSERT(outer.contains(inner));
1753 //
1754 // For now at least check for containment of bounds
1755 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1756
1757 this->onDrawDRRect(outer, inner, paint);
1758}
1759
reed41af9662015-01-05 07:49:08 -08001760// These need to stop being virtual -- clients need to override the onDraw... versions
1761
1762void SkCanvas::drawPaint(const SkPaint& paint) {
1763 this->onDrawPaint(paint);
1764}
1765
1766void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1767 this->onDrawRect(r, paint);
1768}
1769
msarettdca352e2016-08-26 06:37:45 -07001770void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1771 if (region.isEmpty()) {
1772 return;
1773 }
1774
1775 if (region.isRect()) {
1776 return this->drawIRect(region.getBounds(), paint);
1777 }
1778
1779 this->onDrawRegion(region, paint);
1780}
1781
reed41af9662015-01-05 07:49:08 -08001782void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1783 this->onDrawOval(r, paint);
1784}
1785
1786void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1787 this->onDrawRRect(rrect, paint);
1788}
1789
1790void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1791 this->onDrawPoints(mode, count, pts, paint);
1792}
1793
1794void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001795 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001796 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001797 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1798 indexCount, paint);
1799}
1800
1801void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1802 uint32_t flags) {
1803 RETURN_ON_NULL(vertices);
1804 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001805}
1806
1807void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1808 this->onDrawPath(path, paint);
1809}
1810
reeda85d4d02015-05-06 12:56:48 -07001811void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001812 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001813 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001814}
1815
reede47829b2015-08-06 10:02:53 -07001816void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1817 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001818 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001819 if (dst.isEmpty() || src.isEmpty()) {
1820 return;
1821 }
1822 this->onDrawImageRect(image, &src, dst, paint, constraint);
1823}
reed41af9662015-01-05 07:49:08 -08001824
reed84984ef2015-07-17 07:09:43 -07001825void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1826 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001827 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001828 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001829}
1830
reede47829b2015-08-06 10:02:53 -07001831void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1832 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001833 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001834 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1835 constraint);
1836}
reede47829b2015-08-06 10:02:53 -07001837
reed4c21dc52015-06-25 12:32:03 -07001838void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1839 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001840 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001841 if (dst.isEmpty()) {
1842 return;
1843 }
msarett552bca92016-08-03 06:53:26 -07001844 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1845 this->onDrawImageNine(image, center, dst, paint);
1846 } else {
reede47829b2015-08-06 10:02:53 -07001847 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001848 }
reed4c21dc52015-06-25 12:32:03 -07001849}
1850
msarett16882062016-08-16 09:31:08 -07001851void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1852 const SkPaint* paint) {
1853 RETURN_ON_NULL(image);
1854 if (dst.isEmpty()) {
1855 return;
1856 }
msarett71df2d72016-09-30 12:41:42 -07001857
1858 SkIRect bounds;
1859 Lattice latticePlusBounds = lattice;
1860 if (!latticePlusBounds.fBounds) {
1861 bounds = SkIRect::MakeWH(image->width(), image->height());
1862 latticePlusBounds.fBounds = &bounds;
1863 }
1864
1865 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1866 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001867 } else {
1868 this->drawImageRect(image, dst, paint);
1869 }
1870}
1871
reed41af9662015-01-05 07:49:08 -08001872void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001873 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001874 return;
1875 }
reed41af9662015-01-05 07:49:08 -08001876 this->onDrawBitmap(bitmap, dx, dy, paint);
1877}
1878
reede47829b2015-08-06 10:02:53 -07001879void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001880 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001881 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001882 return;
1883 }
reede47829b2015-08-06 10:02:53 -07001884 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001885}
1886
reed84984ef2015-07-17 07:09:43 -07001887void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1888 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001889 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001890}
1891
reede47829b2015-08-06 10:02:53 -07001892void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1893 SrcRectConstraint constraint) {
1894 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1895 constraint);
1896}
reede47829b2015-08-06 10:02:53 -07001897
reed41af9662015-01-05 07:49:08 -08001898void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1899 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001900 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001901 return;
1902 }
msarett552bca92016-08-03 06:53:26 -07001903 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1904 this->onDrawBitmapNine(bitmap, center, dst, paint);
1905 } else {
reeda5517e22015-07-14 10:54:12 -07001906 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001907 }
reed41af9662015-01-05 07:49:08 -08001908}
1909
msarettc573a402016-08-02 08:05:56 -07001910void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1911 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001912 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001913 return;
1914 }
msarett71df2d72016-09-30 12:41:42 -07001915
1916 SkIRect bounds;
1917 Lattice latticePlusBounds = lattice;
1918 if (!latticePlusBounds.fBounds) {
1919 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1920 latticePlusBounds.fBounds = &bounds;
1921 }
1922
1923 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1924 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001925 } else {
msarett16882062016-08-16 09:31:08 -07001926 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001927 }
msarettc573a402016-08-02 08:05:56 -07001928}
1929
reed71c3c762015-06-24 10:29:17 -07001930void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001931 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001932 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001933 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001934 if (count <= 0) {
1935 return;
1936 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001937 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001938 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001939 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001940}
1941
reedf70b5312016-03-04 16:36:20 -08001942void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1943 if (key) {
1944 this->onDrawAnnotation(rect, key, value);
1945 }
1946}
1947
reede47829b2015-08-06 10:02:53 -07001948void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1949 const SkPaint* paint, SrcRectConstraint constraint) {
1950 if (src) {
1951 this->drawImageRect(image, *src, dst, paint, constraint);
1952 } else {
1953 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1954 dst, paint, constraint);
1955 }
1956}
1957void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1958 const SkPaint* paint, SrcRectConstraint constraint) {
1959 if (src) {
1960 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1961 } else {
1962 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1963 dst, paint, constraint);
1964 }
1965}
1966
tomhudsoncb3bd182016-05-18 07:24:16 -07001967void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1968 SkIRect layer_bounds = this->getTopLayerBounds();
1969 if (matrix) {
1970 *matrix = this->getTotalMatrix();
1971 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1972 }
1973 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001974 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001975 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1976 }
1977}
1978
reed@android.com8a1c16f2008-12-17 15:59:43 +00001979//////////////////////////////////////////////////////////////////////////////
1980// These are the virtual drawing methods
1981//////////////////////////////////////////////////////////////////////////////
1982
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001983void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001984 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001985 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1986 }
1987}
1988
reed41af9662015-01-05 07:49:08 -08001989void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001990 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001991 this->internalDrawPaint(paint);
1992}
1993
1994void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001995 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001996
1997 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001998 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999 }
2000
reed@google.com4e2b3d32011-04-07 14:18:59 +00002001 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002002}
2003
reed41af9662015-01-05 07:49:08 -08002004void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2005 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002006 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002007 if ((long)count <= 0) {
2008 return;
2009 }
2010
Mike Reed822128b2017-02-28 16:41:03 -05002011 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002012 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002013 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002014 // special-case 2 points (common for drawing a single line)
2015 if (2 == count) {
2016 r.set(pts[0], pts[1]);
2017 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002018 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002019 }
Mike Reed822128b2017-02-28 16:41:03 -05002020 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002021 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2022 return;
2023 }
2024 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002025 }
reed@google.coma584aed2012-05-16 14:06:02 +00002026
halcanary96fcdcc2015-08-27 07:41:13 -07002027 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002028
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002029 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002030
reed@android.com8a1c16f2008-12-17 15:59:43 +00002031 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002032 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002033 }
reed@google.com4b226022011-01-11 18:32:13 +00002034
reed@google.com4e2b3d32011-04-07 14:18:59 +00002035 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002036}
2037
reed4a167172016-08-18 17:15:25 -07002038static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2039 return ((intptr_t)paint.getImageFilter() |
2040#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2041 (intptr_t)canvas->getDrawFilter() |
2042#endif
2043 (intptr_t)paint.getLooper() ) != 0;
2044}
2045
reed41af9662015-01-05 07:49:08 -08002046void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002047 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002048 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002049 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2050 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2051 SkRect tmp(r);
2052 tmp.sort();
2053
Mike Reed822128b2017-02-28 16:41:03 -05002054 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002055 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2056 return;
2057 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002058 }
reed@google.com4b226022011-01-11 18:32:13 +00002059
reed4a167172016-08-18 17:15:25 -07002060 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002061 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002062
reed4a167172016-08-18 17:15:25 -07002063 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002064 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002065 }
2066
2067 LOOPER_END
2068 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002069 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002070 SkDrawIter iter(this);
2071 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002072 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002073 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002074 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002075}
2076
msarett44df6512016-08-25 13:54:30 -07002077void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002078 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002079 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002080 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002081 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2082 return;
2083 }
msarett44df6512016-08-25 13:54:30 -07002084 }
2085
Mike Reed822128b2017-02-28 16:41:03 -05002086 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002087
2088 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002089 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002090 }
2091
2092 LOOPER_END
2093}
2094
reed41af9662015-01-05 07:49:08 -08002095void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002096 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002097 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002098 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002099 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2100 return;
2101 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002102 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002103
Mike Reed822128b2017-02-28 16:41:03 -05002104 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002105
2106 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002107 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002108 }
2109
2110 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002111}
2112
bsalomonac3aa242016-08-19 11:25:19 -07002113void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2114 SkScalar sweepAngle, bool useCenter,
2115 const SkPaint& paint) {
2116 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002117 if (paint.canComputeFastBounds()) {
2118 SkRect storage;
2119 // Note we're using the entire oval as the bounds.
2120 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2121 return;
2122 }
bsalomonac3aa242016-08-19 11:25:19 -07002123 }
2124
Mike Reed822128b2017-02-28 16:41:03 -05002125 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002126
2127 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002128 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002129 }
2130
2131 LOOPER_END
2132}
2133
reed41af9662015-01-05 07:49:08 -08002134void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002135 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002136 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002137 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002138 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2139 return;
2140 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002141 }
2142
2143 if (rrect.isRect()) {
2144 // call the non-virtual version
2145 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002146 return;
2147 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002148 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002149 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2150 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002151 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002152
Mike Reed822128b2017-02-28 16:41:03 -05002153 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002154
2155 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002156 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002157 }
2158
2159 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002160}
2161
Mike Reed822128b2017-02-28 16:41:03 -05002162void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002163 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002164 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002165 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2166 return;
2167 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002168 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002169
Mike Reed822128b2017-02-28 16:41:03 -05002170 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002171
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002172 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002173 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002174 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002175
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002176 LOOPER_END
2177}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002178
reed41af9662015-01-05 07:49:08 -08002179void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002180 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002181 if (!path.isFinite()) {
2182 return;
2183 }
2184
Mike Reed822128b2017-02-28 16:41:03 -05002185 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002186 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002187 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002188 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2189 return;
2190 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002191 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002192
Mike Reed822128b2017-02-28 16:41:03 -05002193 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002194 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002195 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002196 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002197 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002198 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002199
Mike Reed822128b2017-02-28 16:41:03 -05002200 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002201
2202 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002203 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002204 }
2205
reed@google.com4e2b3d32011-04-07 14:18:59 +00002206 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002207}
2208
reed262a71b2015-12-05 13:07:27 -08002209bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002210 if (!paint.getImageFilter()) {
2211 return false;
2212 }
2213
2214 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002215 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002216 return false;
2217 }
2218
2219 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2220 // Once we can filter and the filter will return a result larger than itself, we should be
2221 // able to remove this constraint.
2222 // skbug.com/4526
2223 //
2224 SkPoint pt;
2225 ctm.mapXY(x, y, &pt);
2226 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2227 return ir.contains(fMCRec->fRasterClip.getBounds());
2228}
2229
reeda85d4d02015-05-06 12:56:48 -07002230void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002231 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002232 SkRect bounds = SkRect::MakeXYWH(x, y,
2233 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002234 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002235 SkRect tmp = bounds;
2236 if (paint) {
2237 paint->computeFastBounds(tmp, &tmp);
2238 }
2239 if (this->quickReject(tmp)) {
2240 return;
2241 }
reeda85d4d02015-05-06 12:56:48 -07002242 }
halcanary9d524f22016-03-29 09:03:52 -07002243
reeda85d4d02015-05-06 12:56:48 -07002244 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002245 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002246 paint = lazy.init();
2247 }
reed262a71b2015-12-05 13:07:27 -08002248
reeda2217ef2016-07-20 06:04:34 -07002249 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002250 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2251 *paint);
2252 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002253 special = this->getDevice()->makeSpecial(image);
2254 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002255 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002256 }
2257 }
2258
reed262a71b2015-12-05 13:07:27 -08002259 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2260
reeda85d4d02015-05-06 12:56:48 -07002261 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002262 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002263 if (special) {
2264 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002265 iter.fDevice->ctm().mapXY(x, y, &pt);
2266 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002267 SkScalarRoundToInt(pt.fX),
2268 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002269 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002270 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002271 }
reeda85d4d02015-05-06 12:56:48 -07002272 }
halcanary9d524f22016-03-29 09:03:52 -07002273
reeda85d4d02015-05-06 12:56:48 -07002274 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002275}
2276
reed41af9662015-01-05 07:49:08 -08002277void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002278 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002279 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002280 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002281 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002282 if (paint) {
2283 paint->computeFastBounds(dst, &storage);
2284 }
2285 if (this->quickReject(storage)) {
2286 return;
2287 }
reeda85d4d02015-05-06 12:56:48 -07002288 }
2289 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002290 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002291 paint = lazy.init();
2292 }
halcanary9d524f22016-03-29 09:03:52 -07002293
senorblancoc41e7e12015-12-07 12:51:30 -08002294 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002295 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002296
reeda85d4d02015-05-06 12:56:48 -07002297 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002298 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002299 }
halcanary9d524f22016-03-29 09:03:52 -07002300
reeda85d4d02015-05-06 12:56:48 -07002301 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002302}
2303
reed41af9662015-01-05 07:49:08 -08002304void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002305 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002306 SkDEBUGCODE(bitmap.validate();)
2307
reed33366972015-10-08 09:22:02 -07002308 if (bitmap.drawsNothing()) {
2309 return;
2310 }
2311
2312 SkLazyPaint lazy;
2313 if (nullptr == paint) {
2314 paint = lazy.init();
2315 }
2316
Mike Reed822128b2017-02-28 16:41:03 -05002317 SkRect bounds;
2318 bitmap.getBounds(&bounds);
2319 bounds.offset(x, y);
2320 bool canFastBounds = paint->canComputeFastBounds();
2321 if (canFastBounds) {
2322 SkRect storage;
2323 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002324 return;
2325 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002326 }
reed@google.com4b226022011-01-11 18:32:13 +00002327
reeda2217ef2016-07-20 06:04:34 -07002328 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002329 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2330 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002331 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002332 special = this->getDevice()->makeSpecial(bitmap);
2333 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002334 drawAsSprite = false;
2335 }
2336 }
2337
Mike Reed822128b2017-02-28 16:41:03 -05002338 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2339
2340 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002341
2342 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002343 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002344 if (special) {
reed262a71b2015-12-05 13:07:27 -08002345 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002346 iter.fDevice->ctm().mapXY(x, y, &pt);
2347 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002348 SkScalarRoundToInt(pt.fX),
2349 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002350 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002351 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002352 }
reed33366972015-10-08 09:22:02 -07002353 }
msarettfbfa2582016-08-12 08:29:08 -07002354
reed33366972015-10-08 09:22:02 -07002355 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002356}
2357
reed@google.com9987ec32011-09-07 11:57:52 +00002358// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002359void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002360 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002361 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002362 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002363 return;
2364 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002365
halcanary96fcdcc2015-08-27 07:41:13 -07002366 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002367 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002368 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2369 return;
2370 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002371 }
reed@google.com3d608122011-11-21 15:16:16 +00002372
reed@google.com33535f32012-09-25 15:37:50 +00002373 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002374 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002375 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002376 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002377
senorblancoc41e7e12015-12-07 12:51:30 -08002378 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002379 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002380
reed@google.com33535f32012-09-25 15:37:50 +00002381 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002382 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002383 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002384
reed@google.com33535f32012-09-25 15:37:50 +00002385 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002386}
2387
reed41af9662015-01-05 07:49:08 -08002388void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002389 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002390 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002391 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002392 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002393}
2394
reed4c21dc52015-06-25 12:32:03 -07002395void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2396 const SkPaint* paint) {
2397 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002398
halcanary96fcdcc2015-08-27 07:41:13 -07002399 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002400 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002401 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2402 return;
2403 }
reed@google.com3d608122011-11-21 15:16:16 +00002404 }
halcanary9d524f22016-03-29 09:03:52 -07002405
reed4c21dc52015-06-25 12:32:03 -07002406 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002407 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002408 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002409 }
halcanary9d524f22016-03-29 09:03:52 -07002410
senorblancoc41e7e12015-12-07 12:51:30 -08002411 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002412
reed4c21dc52015-06-25 12:32:03 -07002413 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002414 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002415 }
halcanary9d524f22016-03-29 09:03:52 -07002416
reed4c21dc52015-06-25 12:32:03 -07002417 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002418}
2419
reed41af9662015-01-05 07:49:08 -08002420void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2421 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002422 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002423 SkDEBUGCODE(bitmap.validate();)
2424
halcanary96fcdcc2015-08-27 07:41:13 -07002425 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002426 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002427 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2428 return;
2429 }
reed4c21dc52015-06-25 12:32:03 -07002430 }
halcanary9d524f22016-03-29 09:03:52 -07002431
reed4c21dc52015-06-25 12:32:03 -07002432 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002433 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002434 paint = lazy.init();
2435 }
halcanary9d524f22016-03-29 09:03:52 -07002436
senorblancoc41e7e12015-12-07 12:51:30 -08002437 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002438
reed4c21dc52015-06-25 12:32:03 -07002439 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002440 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002441 }
halcanary9d524f22016-03-29 09:03:52 -07002442
reed4c21dc52015-06-25 12:32:03 -07002443 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002444}
2445
msarett16882062016-08-16 09:31:08 -07002446void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2447 const SkPaint* paint) {
2448 if (nullptr == paint || paint->canComputeFastBounds()) {
2449 SkRect storage;
2450 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2451 return;
2452 }
2453 }
2454
2455 SkLazyPaint lazy;
2456 if (nullptr == paint) {
2457 paint = lazy.init();
2458 }
2459
2460 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2461
2462 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002463 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002464 }
2465
2466 LOOPER_END
2467}
2468
2469void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2470 const SkRect& dst, const SkPaint* paint) {
2471 if (nullptr == paint || paint->canComputeFastBounds()) {
2472 SkRect storage;
2473 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2474 return;
2475 }
2476 }
2477
2478 SkLazyPaint lazy;
2479 if (nullptr == paint) {
2480 paint = lazy.init();
2481 }
2482
2483 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2484
2485 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002486 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002487 }
2488
2489 LOOPER_END
2490}
2491
reed@google.comf67e4cf2011-03-15 20:56:58 +00002492class SkDeviceFilteredPaint {
2493public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002494 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002495 uint32_t filteredFlags = device->filterTextFlags(paint);
2496 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002497 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002498 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002499 fPaint = newPaint;
2500 } else {
2501 fPaint = &paint;
2502 }
2503 }
2504
reed@google.comf67e4cf2011-03-15 20:56:58 +00002505 const SkPaint& paint() const { return *fPaint; }
2506
2507private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002508 const SkPaint* fPaint;
2509 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002510};
2511
reed@google.come0d9ce82014-04-23 04:00:17 +00002512void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2513 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002514 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002515
2516 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002517 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002518 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002519 }
2520
reed@google.com4e2b3d32011-04-07 14:18:59 +00002521 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002522}
2523
reed@google.come0d9ce82014-04-23 04:00:17 +00002524void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2525 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002526 SkPoint textOffset = SkPoint::Make(0, 0);
2527
halcanary96fcdcc2015-08-27 07:41:13 -07002528 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002529
reed@android.com8a1c16f2008-12-17 15:59:43 +00002530 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002531 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002532 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002533 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002534 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002535
reed@google.com4e2b3d32011-04-07 14:18:59 +00002536 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002537}
2538
reed@google.come0d9ce82014-04-23 04:00:17 +00002539void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2540 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002541
2542 SkPoint textOffset = SkPoint::Make(0, constY);
2543
halcanary96fcdcc2015-08-27 07:41:13 -07002544 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002545
reed@android.com8a1c16f2008-12-17 15:59:43 +00002546 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002547 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002548 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002549 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002550 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002551
reed@google.com4e2b3d32011-04-07 14:18:59 +00002552 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002553}
2554
reed@google.come0d9ce82014-04-23 04:00:17 +00002555void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2556 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002557 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002558
reed@android.com8a1c16f2008-12-17 15:59:43 +00002559 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002560 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002561 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002562 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002563
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002564 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002565}
2566
reed45561a02016-07-07 12:47:17 -07002567void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2568 const SkRect* cullRect, const SkPaint& paint) {
2569 if (cullRect && this->quickReject(*cullRect)) {
2570 return;
2571 }
2572
2573 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2574
2575 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002576 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002577 }
2578
2579 LOOPER_END
2580}
2581
fmalita00d5c2c2014-08-21 08:53:26 -07002582void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2583 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002584
fmalita85d5eb92015-03-04 11:20:12 -08002585 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002586 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002587 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002588 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002589 SkRect tmp;
2590 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2591 return;
2592 }
2593 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002594 }
2595
fmalita024f9962015-03-03 19:08:17 -08002596 // We cannot filter in the looper as we normally do, because the paint is
2597 // incomplete at this point (text-related attributes are embedded within blob run paints).
2598 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002599 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002600
fmalita85d5eb92015-03-04 11:20:12 -08002601 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002602
fmalitaaa1b9122014-08-28 14:32:24 -07002603 while (iter.next()) {
2604 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002605 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002606 }
2607
fmalitaaa1b9122014-08-28 14:32:24 -07002608 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002609
2610 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002611}
2612
reed@google.come0d9ce82014-04-23 04:00:17 +00002613// These will become non-virtual, so they always call the (virtual) onDraw... method
2614void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2615 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002616 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002617 if (byteLength) {
2618 this->onDrawText(text, byteLength, x, y, paint);
2619 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002620}
2621void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2622 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002623 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002624 if (byteLength) {
2625 this->onDrawPosText(text, byteLength, pos, paint);
2626 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002627}
2628void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2629 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002630 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002631 if (byteLength) {
2632 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2633 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002634}
2635void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2636 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002637 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002638 if (byteLength) {
2639 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2640 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002641}
reed45561a02016-07-07 12:47:17 -07002642void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2643 const SkRect* cullRect, const SkPaint& paint) {
2644 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2645 if (byteLength) {
2646 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2647 }
2648}
fmalita00d5c2c2014-08-21 08:53:26 -07002649void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2650 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002651 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002652 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002653 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002654}
reed@google.come0d9ce82014-04-23 04:00:17 +00002655
reed41af9662015-01-05 07:49:08 -08002656void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2657 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002658 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002659 const uint16_t indices[], int indexCount,
2660 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002661 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002662 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002663
reed@android.com8a1c16f2008-12-17 15:59:43 +00002664 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002665 iter.fDevice->drawVertices(vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002666 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002667 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002668 }
reed@google.com4b226022011-01-11 18:32:13 +00002669
reed@google.com4e2b3d32011-04-07 14:18:59 +00002670 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002671}
2672
Brian Salomon199fb872017-02-06 09:41:10 -05002673void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2674 const SkPaint& paint, uint32_t flags) {
2675 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2676 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2677
2678 while (iter.next()) {
2679 // In the common case of one iteration we could std::move vertices here.
Mike Reeda1361362017-03-07 09:37:29 -05002680 iter.fDevice->drawVerticesObject(vertices, bmode, looper.paint(), flags);
Brian Salomon199fb872017-02-06 09:41:10 -05002681 }
2682
2683 LOOPER_END
2684}
2685
2686void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2687 const SkPaint& paint, uint32_t flags) {
2688 const SkPoint* texs =
2689 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2690 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2691 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2692 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2693}
2694
dandovb3c9d1c2014-08-12 08:34:29 -07002695void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002696 const SkPoint texCoords[4], SkBlendMode bmode,
2697 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002698 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002699 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002700 return;
2701 }
mtklein6cfa73a2014-08-13 13:33:49 -07002702
Mike Reedfaba3712016-11-03 14:45:31 -04002703 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002704}
2705
2706void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002707 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002708 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002709 // Since a patch is always within the convex hull of the control points, we discard it when its
2710 // bounding rectangle is completely outside the current clip.
2711 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002712 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002713 if (this->quickReject(bounds)) {
2714 return;
2715 }
mtklein6cfa73a2014-08-13 13:33:49 -07002716
halcanary96fcdcc2015-08-27 07:41:13 -07002717 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002718
dandovecfff212014-08-04 10:02:00 -07002719 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002720 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002721 }
mtklein6cfa73a2014-08-13 13:33:49 -07002722
dandovecfff212014-08-04 10:02:00 -07002723 LOOPER_END
2724}
2725
reeda8db7282015-07-07 10:22:31 -07002726void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002727 RETURN_ON_NULL(dr);
2728 if (x || y) {
2729 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2730 this->onDrawDrawable(dr, &matrix);
2731 } else {
2732 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002733 }
2734}
2735
reeda8db7282015-07-07 10:22:31 -07002736void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002737 RETURN_ON_NULL(dr);
2738 if (matrix && matrix->isIdentity()) {
2739 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002740 }
reede3b38ce2016-01-08 09:18:44 -08002741 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002742}
2743
2744void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002745 // drawable bounds are no longer reliable (e.g. android displaylist)
2746 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002747 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002748}
2749
reed71c3c762015-06-24 10:29:17 -07002750void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002751 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002752 const SkRect* cull, const SkPaint* paint) {
2753 if (cull && this->quickReject(*cull)) {
2754 return;
2755 }
2756
2757 SkPaint pnt;
2758 if (paint) {
2759 pnt = *paint;
2760 }
halcanary9d524f22016-03-29 09:03:52 -07002761
halcanary96fcdcc2015-08-27 07:41:13 -07002762 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002763 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002764 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002765 }
2766 LOOPER_END
2767}
2768
reedf70b5312016-03-04 16:36:20 -08002769void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2770 SkASSERT(key);
2771
2772 SkPaint paint;
2773 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2774 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002775 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002776 }
2777 LOOPER_END
2778}
2779
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780//////////////////////////////////////////////////////////////////////////////
2781// These methods are NOT virtual, and therefore must call back into virtual
2782// methods, rather than actually drawing themselves.
2783//////////////////////////////////////////////////////////////////////////////
2784
Mike Reed3661bc92017-02-22 13:21:42 -05002785#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed374772b2016-10-05 17:33:02 -07002786void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002787 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002788 SkPaint paint;
2789
2790 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002791 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002792 this->drawPaint(paint);
2793}
Mike Reed3661bc92017-02-22 13:21:42 -05002794#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795
reed374772b2016-10-05 17:33:02 -07002796void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002797 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798 SkPaint paint;
2799
2800 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002801 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002802 this->drawPaint(paint);
2803}
2804
2805void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002806 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002807 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002808 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2809}
2810
Mike Reed3661bc92017-02-22 13:21:42 -05002811#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002813 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814 SkPoint pt;
2815 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002816
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817 pt.set(x, y);
2818 paint.setColor(color);
2819 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2820}
Mike Reed3661bc92017-02-22 13:21:42 -05002821#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002822
Mike Reed3661bc92017-02-22 13:21:42 -05002823void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002824 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002826
reed@android.com8a1c16f2008-12-17 15:59:43 +00002827 pts[0].set(x0, y0);
2828 pts[1].set(x1, y1);
2829 this->drawPoints(kLines_PointMode, 2, pts, paint);
2830}
2831
Mike Reed3661bc92017-02-22 13:21:42 -05002832#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2834 SkScalar right, SkScalar bottom,
2835 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002836 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837 SkRect r;
2838
2839 r.set(left, top, right, bottom);
2840 this->drawRect(r, paint);
2841}
Mike Reed3661bc92017-02-22 13:21:42 -05002842#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002843
Mike Reed3661bc92017-02-22 13:21:42 -05002844void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002845 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002846 if (radius < 0) {
2847 radius = 0;
2848 }
2849
2850 SkRect r;
2851 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002852 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002853}
2854
2855void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2856 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002857 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002858 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002859 SkRRect rrect;
2860 rrect.setRectXY(r, rx, ry);
2861 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002862 } else {
2863 this->drawRect(r, paint);
2864 }
2865}
2866
reed@android.com8a1c16f2008-12-17 15:59:43 +00002867void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2868 SkScalar sweepAngle, bool useCenter,
2869 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002870 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002871 if (oval.isEmpty() || !sweepAngle) {
2872 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002873 }
bsalomon21af9ca2016-08-25 12:29:23 -07002874 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002875}
2876
2877void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2878 const SkPath& path, SkScalar hOffset,
2879 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002880 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002881 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002882
reed@android.com8a1c16f2008-12-17 15:59:43 +00002883 matrix.setTranslate(hOffset, vOffset);
2884 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2885}
2886
reed@android.comf76bacf2009-05-13 14:00:33 +00002887///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002888
2889/**
2890 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2891 * against the playback cost of recursing into the subpicture to get at its actual ops.
2892 *
2893 * For now we pick a conservatively small value, though measurement (and other heuristics like
2894 * the type of ops contained) may justify changing this value.
2895 */
2896#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002897
reedd5fa1a42014-08-09 11:08:05 -07002898void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002899 RETURN_ON_NULL(picture);
2900
reed1c2c4412015-04-30 13:09:24 -07002901 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002902 if (matrix && matrix->isIdentity()) {
2903 matrix = nullptr;
2904 }
2905 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2906 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2907 picture->playback(this);
2908 } else {
2909 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002910 }
2911}
robertphillips9b14f262014-06-04 05:40:44 -07002912
reedd5fa1a42014-08-09 11:08:05 -07002913void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2914 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002915 if (!paint || paint->canComputeFastBounds()) {
2916 SkRect bounds = picture->cullRect();
2917 if (paint) {
2918 paint->computeFastBounds(bounds, &bounds);
2919 }
2920 if (matrix) {
2921 matrix->mapRect(&bounds);
2922 }
2923 if (this->quickReject(bounds)) {
2924 return;
2925 }
2926 }
2927
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002928 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002929 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002930}
2931
vjiaoblack95302da2016-07-21 10:25:54 -07002932#ifdef SK_EXPERIMENTAL_SHADOWING
2933void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2934 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002935 const SkPaint* paint,
2936 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002937 RETURN_ON_NULL(picture);
2938
2939 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2940
vjiaoblacke6f5d562016-08-25 06:30:23 -07002941 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002942}
2943
2944void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2945 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002946 const SkPaint* paint,
2947 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002948 if (!paint || paint->canComputeFastBounds()) {
2949 SkRect bounds = picture->cullRect();
2950 if (paint) {
2951 paint->computeFastBounds(bounds, &bounds);
2952 }
2953 if (matrix) {
2954 matrix->mapRect(&bounds);
2955 }
2956 if (this->quickReject(bounds)) {
2957 return;
2958 }
2959 }
2960
2961 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2962
vjiaoblacke6f5d562016-08-25 06:30:23 -07002963 sk_sp<SkImage> povDepthMap;
2964 sk_sp<SkImage> diffuseMap;
2965
vjiaoblack904527d2016-08-09 09:32:09 -07002966 // povDepthMap
2967 {
2968 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002969 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2970 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002971 sk_sp<SkLights> povLight = builder.finish();
2972
2973 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2974 picture->cullRect().height(),
2975 kBGRA_8888_SkColorType,
2976 kOpaque_SkAlphaType);
2977
2978 // Create a new surface (that matches the backend of canvas)
2979 // to create the povDepthMap
2980 sk_sp<SkSurface> surf(this->makeSurface(info));
2981
2982 // Wrap another SPFCanvas around the surface
2983 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2984 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2985
2986 // set the depth map canvas to have the light as the user's POV
2987 depthMapCanvas->setLights(std::move(povLight));
2988
2989 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002990 povDepthMap = surf->makeImageSnapshot();
2991 }
2992
2993 // diffuseMap
2994 {
2995 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2996 picture->cullRect().height(),
2997 kBGRA_8888_SkColorType,
2998 kOpaque_SkAlphaType);
2999
3000 sk_sp<SkSurface> surf(this->makeSurface(info));
3001 surf->getCanvas()->drawPicture(picture);
3002
3003 diffuseMap = surf->makeImageSnapshot();
3004 }
vjiaoblack904527d2016-08-09 09:32:09 -07003005
3006 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3007 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003008 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3009 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003010
3011 // TODO: pass the depth to the shader in vertices, or uniforms
3012 // so we don't have to render depth and color separately
3013 for (int i = 0; i < fLights->numLights(); ++i) {
3014 // skip over ambient lights; they don't cast shadows
3015 // lights that have shadow maps do not need updating (because lights are immutable)
3016 sk_sp<SkImage> depthMap;
3017 SkISize shMapSize;
3018
3019 if (fLights->light(i).getShadowMap() != nullptr) {
3020 continue;
3021 }
3022
3023 if (fLights->light(i).isRadial()) {
3024 shMapSize.fHeight = 1;
3025 shMapSize.fWidth = (int) picture->cullRect().width();
3026
3027 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3028 kBGRA_8888_SkColorType,
3029 kOpaque_SkAlphaType);
3030
3031 // Create new surface (that matches the backend of canvas)
3032 // for each shadow map
3033 sk_sp<SkSurface> surf(this->makeSurface(info));
3034
3035 // Wrap another SPFCanvas around the surface
3036 SkCanvas* depthMapCanvas = surf->getCanvas();
3037
3038 SkLights::Builder builder;
3039 builder.add(fLights->light(i));
3040 sk_sp<SkLights> curLight = builder.finish();
3041
3042 sk_sp<SkShader> shadowMapShader;
3043 shadowMapShader = SkRadialShadowMapShader::Make(
3044 povDepthShader, curLight,
3045 (int) picture->cullRect().width(),
3046 (int) picture->cullRect().height());
3047
3048 SkPaint shadowMapPaint;
3049 shadowMapPaint.setShader(std::move(shadowMapShader));
3050
3051 depthMapCanvas->setLights(curLight);
3052
3053 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3054 diffuseMap->height()),
3055 shadowMapPaint);
3056
3057 depthMap = surf->makeImageSnapshot();
3058
3059 } else {
3060 // TODO: compute the correct size of the depth map from the light properties
3061 // TODO: maybe add a kDepth_8_SkColorType
3062 // TODO: find actual max depth of picture
3063 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3064 fLights->light(i), 255,
3065 (int) picture->cullRect().width(),
3066 (int) picture->cullRect().height());
3067
3068 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3069 kBGRA_8888_SkColorType,
3070 kOpaque_SkAlphaType);
3071
3072 // Create a new surface (that matches the backend of canvas)
3073 // for each shadow map
3074 sk_sp<SkSurface> surf(this->makeSurface(info));
3075
3076 // Wrap another SPFCanvas around the surface
3077 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3078 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3079 depthMapCanvas->setShadowParams(params);
3080
3081 // set the depth map canvas to have the light we're drawing.
3082 SkLights::Builder builder;
3083 builder.add(fLights->light(i));
3084 sk_sp<SkLights> curLight = builder.finish();
3085 depthMapCanvas->setLights(std::move(curLight));
3086
3087 depthMapCanvas->drawPicture(picture);
3088 depthMap = surf->makeImageSnapshot();
3089 }
3090
3091 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3092 fLights->light(i).setShadowMap(std::move(depthMap));
3093 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3094 // we blur the variance map
3095 SkPaint blurPaint;
3096 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3097 params.fShadowRadius, nullptr));
3098
3099 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3100 kBGRA_8888_SkColorType,
3101 kOpaque_SkAlphaType);
3102
3103 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3104
3105 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3106
3107 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3108 }
3109 }
3110
3111 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003112 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3113 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003114 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003115 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003116 diffuseMap->height(),
3117 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003118
3119 shadowPaint.setShader(shadowShader);
3120
3121 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003122}
3123#endif
3124
reed@android.com8a1c16f2008-12-17 15:59:43 +00003125///////////////////////////////////////////////////////////////////////////////
3126///////////////////////////////////////////////////////////////////////////////
3127
reed3aafe112016-08-18 12:45:34 -07003128SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003129 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003130
3131 SkASSERT(canvas);
3132
reed3aafe112016-08-18 12:45:34 -07003133 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003134 fDone = !fImpl->next();
3135}
3136
3137SkCanvas::LayerIter::~LayerIter() {
3138 fImpl->~SkDrawIter();
3139}
3140
3141void SkCanvas::LayerIter::next() {
3142 fDone = !fImpl->next();
3143}
3144
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003145SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003146 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003147}
3148
3149const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003150 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003151}
3152
3153const SkPaint& SkCanvas::LayerIter::paint() const {
3154 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003155 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003156 paint = &fDefaultPaint;
3157 }
3158 return *paint;
3159}
3160
Mike Reeda1361362017-03-07 09:37:29 -05003161void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3162 return fImpl->fDevice->onAsRgnClip(rgn);
3163}
3164
reed@android.com8a1c16f2008-12-17 15:59:43 +00003165int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3166int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003167
3168///////////////////////////////////////////////////////////////////////////////
3169
Mike Reed8310f0e2017-03-08 21:42:37 +00003170SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
3171
3172///////////////////////////////////////////////////////////////////////////////
3173
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003174static bool supported_for_raster_canvas(const SkImageInfo& info) {
3175 switch (info.alphaType()) {
3176 case kPremul_SkAlphaType:
3177 case kOpaque_SkAlphaType:
3178 break;
3179 default:
3180 return false;
3181 }
3182
3183 switch (info.colorType()) {
3184 case kAlpha_8_SkColorType:
3185 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003186 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003187 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003188 break;
3189 default:
3190 return false;
3191 }
3192
3193 return true;
3194}
3195
Mike Reed5df49342016-11-12 08:06:55 -06003196std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3197 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003198 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003199 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003200 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003201
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003202 SkBitmap bitmap;
3203 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003204 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003205 }
Mike Reed5df49342016-11-12 08:06:55 -06003206 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003207}
reedd5fa1a42014-08-09 11:08:05 -07003208
3209///////////////////////////////////////////////////////////////////////////////
3210
3211SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003212 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003213 : fCanvas(canvas)
3214 , fSaveCount(canvas->getSaveCount())
3215{
bsalomon49f085d2014-09-05 13:34:00 -07003216 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003217 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003218 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003219 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003220 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003221 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003222 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003223 canvas->save();
3224 }
mtklein6cfa73a2014-08-13 13:33:49 -07003225
bsalomon49f085d2014-09-05 13:34:00 -07003226 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003227 canvas->concat(*matrix);
3228 }
3229}
3230
3231SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3232 fCanvas->restoreToCount(fSaveCount);
3233}
reede8f30622016-03-23 18:59:25 -07003234
Florin Malitaee424ac2016-12-01 12:47:59 -05003235///////////////////////////////////////////////////////////////////////////////
3236
3237SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3238 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3239
Florin Malita439ace92016-12-02 12:05:41 -05003240SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3241 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3242
Florin Malitaee424ac2016-12-01 12:47:59 -05003243SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3244 (void)this->INHERITED::getSaveLayerStrategy(rec);
3245 return kNoLayer_SaveLayerStrategy;
3246}
3247
3248///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003249
reed73603f32016-09-20 08:42:38 -07003250static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3251static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3252static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3253static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3254static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3255static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003256
3257///////////////////////////////////////////////////////////////////////////////////////////////////
3258
3259SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3260 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3261 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3262 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3263 SkIPoint origin = dev->getOrigin();
3264 SkMatrix ctm = this->getTotalMatrix();
3265 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3266
3267 SkIRect clip = fMCRec->fRasterClip.getBounds();
3268 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003269 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003270 clip.setEmpty();
3271 }
3272
3273 fAllocator->updateHandle(handle, ctm, clip);
3274 return handle;
3275 }
3276 return nullptr;
3277}
3278
3279static bool install(SkBitmap* bm, const SkImageInfo& info,
3280 const SkRasterHandleAllocator::Rec& rec) {
3281 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3282 rec.fReleaseProc, rec.fReleaseCtx);
3283}
3284
3285SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3286 SkBitmap* bm) {
3287 SkRasterHandleAllocator::Rec rec;
3288 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3289 return nullptr;
3290 }
3291 return rec.fHandle;
3292}
3293
3294std::unique_ptr<SkCanvas>
3295SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3296 const SkImageInfo& info, const Rec* rec) {
3297 if (!alloc || !supported_for_raster_canvas(info)) {
3298 return nullptr;
3299 }
3300
3301 SkBitmap bm;
3302 Handle hndl;
3303
3304 if (rec) {
3305 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3306 } else {
3307 hndl = alloc->allocBitmap(info, &bm);
3308 }
3309 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3310}