blob: 45acc535d74cdcaabb12b54e802d4c169f6807c8 [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 {
Mike Reede393a622017-03-10 16:35:25 -050061 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
62 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050063 }
Mike Reed139e5e02017-03-08 11:29:33 -050064
65 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050066 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050067 this->privateResize(bounds.width(), bounds.height());
68 }
69
70protected:
71 // We don't track the clip at all (for performance), but we have to respond to some queries.
72 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
73 void onSave() override {}
74 void onRestore() override {}
75 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
76 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
77 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
78 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
79 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
80 bool onClipIsAA() const override { return false; }
81 void onAsRgnClip(SkRegion* rgn) const override {
82 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
83 }
84 ClipType onGetClipType() const override {
85 return kRect_ClipType;
86 }
87
88 void drawPaint(const SkPaint& paint) override {}
89 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
90 void drawRect(const SkRect&, const SkPaint&) override {}
91 void drawOval(const SkRect&, const SkPaint&) override {}
92 void drawRRect(const SkRRect&, const SkPaint&) override {}
93 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
94 void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {}
95 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
96 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
97 SkCanvas::SrcRectConstraint) override {}
98 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
99 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
100 const SkPaint&) override {}
101 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
Mike Reed2f6b5a42017-03-19 15:04:17 -0400102 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -0500103
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
Mike Reedfed9cfd2017-03-17 12:09:04 -04001794void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint positions[],
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) {
Mike Reedfed9cfd2017-03-17 12:09:04 -04001797 auto vertices = SkVertices::MakeCopy(vmode, vertexCount, positions, texs, colors,
1798 indexCount, indices);
1799 if (vertices) {
1800 this->onDrawVerticesObject(vertices.get(), bmode, paint);
1801 }
Brian Salomon199fb872017-02-06 09:41:10 -05001802}
1803
Mike Reede88a1cb2017-03-17 09:50:46 -04001804void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1805 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001806 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001807 this->onDrawVerticesObject(vertices.get(), mode, paint);
1808}
1809
1810void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1811 RETURN_ON_NULL(vertices);
1812 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001813}
1814
1815void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1816 this->onDrawPath(path, paint);
1817}
1818
reeda85d4d02015-05-06 12:56:48 -07001819void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001820 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001821 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001822}
1823
reede47829b2015-08-06 10:02:53 -07001824void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1825 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001826 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001827 if (dst.isEmpty() || src.isEmpty()) {
1828 return;
1829 }
1830 this->onDrawImageRect(image, &src, dst, paint, constraint);
1831}
reed41af9662015-01-05 07:49:08 -08001832
reed84984ef2015-07-17 07:09:43 -07001833void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1834 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001835 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001836 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001837}
1838
reede47829b2015-08-06 10:02:53 -07001839void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1840 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001841 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001842 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1843 constraint);
1844}
reede47829b2015-08-06 10:02:53 -07001845
reed4c21dc52015-06-25 12:32:03 -07001846void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1847 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001848 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001849 if (dst.isEmpty()) {
1850 return;
1851 }
msarett552bca92016-08-03 06:53:26 -07001852 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1853 this->onDrawImageNine(image, center, dst, paint);
1854 } else {
reede47829b2015-08-06 10:02:53 -07001855 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001856 }
reed4c21dc52015-06-25 12:32:03 -07001857}
1858
msarett16882062016-08-16 09:31:08 -07001859void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1860 const SkPaint* paint) {
1861 RETURN_ON_NULL(image);
1862 if (dst.isEmpty()) {
1863 return;
1864 }
msarett71df2d72016-09-30 12:41:42 -07001865
1866 SkIRect bounds;
1867 Lattice latticePlusBounds = lattice;
1868 if (!latticePlusBounds.fBounds) {
1869 bounds = SkIRect::MakeWH(image->width(), image->height());
1870 latticePlusBounds.fBounds = &bounds;
1871 }
1872
1873 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1874 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001875 } else {
1876 this->drawImageRect(image, dst, paint);
1877 }
1878}
1879
reed41af9662015-01-05 07:49:08 -08001880void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001881 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001882 return;
1883 }
reed41af9662015-01-05 07:49:08 -08001884 this->onDrawBitmap(bitmap, dx, dy, paint);
1885}
1886
reede47829b2015-08-06 10:02:53 -07001887void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001888 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001889 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001890 return;
1891 }
reede47829b2015-08-06 10:02:53 -07001892 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001893}
1894
reed84984ef2015-07-17 07:09:43 -07001895void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1896 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001897 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001898}
1899
reede47829b2015-08-06 10:02:53 -07001900void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1901 SrcRectConstraint constraint) {
1902 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1903 constraint);
1904}
reede47829b2015-08-06 10:02:53 -07001905
reed41af9662015-01-05 07:49:08 -08001906void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1907 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001908 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001909 return;
1910 }
msarett552bca92016-08-03 06:53:26 -07001911 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1912 this->onDrawBitmapNine(bitmap, center, dst, paint);
1913 } else {
reeda5517e22015-07-14 10:54:12 -07001914 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001915 }
reed41af9662015-01-05 07:49:08 -08001916}
1917
msarettc573a402016-08-02 08:05:56 -07001918void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1919 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001920 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001921 return;
1922 }
msarett71df2d72016-09-30 12:41:42 -07001923
1924 SkIRect bounds;
1925 Lattice latticePlusBounds = lattice;
1926 if (!latticePlusBounds.fBounds) {
1927 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1928 latticePlusBounds.fBounds = &bounds;
1929 }
1930
1931 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1932 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001933 } else {
msarett16882062016-08-16 09:31:08 -07001934 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001935 }
msarettc573a402016-08-02 08:05:56 -07001936}
1937
reed71c3c762015-06-24 10:29:17 -07001938void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001939 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001940 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001941 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001942 if (count <= 0) {
1943 return;
1944 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001945 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001946 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001947 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001948}
1949
reedf70b5312016-03-04 16:36:20 -08001950void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1951 if (key) {
1952 this->onDrawAnnotation(rect, key, value);
1953 }
1954}
1955
reede47829b2015-08-06 10:02:53 -07001956void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1957 const SkPaint* paint, SrcRectConstraint constraint) {
1958 if (src) {
1959 this->drawImageRect(image, *src, dst, paint, constraint);
1960 } else {
1961 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1962 dst, paint, constraint);
1963 }
1964}
1965void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1966 const SkPaint* paint, SrcRectConstraint constraint) {
1967 if (src) {
1968 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1969 } else {
1970 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1971 dst, paint, constraint);
1972 }
1973}
1974
tomhudsoncb3bd182016-05-18 07:24:16 -07001975void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1976 SkIRect layer_bounds = this->getTopLayerBounds();
1977 if (matrix) {
1978 *matrix = this->getTotalMatrix();
1979 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1980 }
1981 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001982 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001983 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1984 }
1985}
1986
reed@android.com8a1c16f2008-12-17 15:59:43 +00001987//////////////////////////////////////////////////////////////////////////////
1988// These are the virtual drawing methods
1989//////////////////////////////////////////////////////////////////////////////
1990
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001991void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001992 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001993 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1994 }
1995}
1996
reed41af9662015-01-05 07:49:08 -08001997void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001998 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001999 this->internalDrawPaint(paint);
2000}
2001
2002void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002003 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004
2005 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002006 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002007 }
2008
reed@google.com4e2b3d32011-04-07 14:18:59 +00002009 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002010}
2011
reed41af9662015-01-05 07:49:08 -08002012void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2013 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002014 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002015 if ((long)count <= 0) {
2016 return;
2017 }
2018
Mike Reed822128b2017-02-28 16:41:03 -05002019 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002020 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002021 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002022 // special-case 2 points (common for drawing a single line)
2023 if (2 == count) {
2024 r.set(pts[0], pts[1]);
2025 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002026 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002027 }
Mike Reed822128b2017-02-28 16:41:03 -05002028 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002029 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2030 return;
2031 }
2032 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002033 }
reed@google.coma584aed2012-05-16 14:06:02 +00002034
halcanary96fcdcc2015-08-27 07:41:13 -07002035 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002036
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002037 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002038
reed@android.com8a1c16f2008-12-17 15:59:43 +00002039 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002040 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002041 }
reed@google.com4b226022011-01-11 18:32:13 +00002042
reed@google.com4e2b3d32011-04-07 14:18:59 +00002043 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002044}
2045
reed4a167172016-08-18 17:15:25 -07002046static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2047 return ((intptr_t)paint.getImageFilter() |
2048#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2049 (intptr_t)canvas->getDrawFilter() |
2050#endif
2051 (intptr_t)paint.getLooper() ) != 0;
2052}
2053
reed41af9662015-01-05 07:49:08 -08002054void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002055 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002056 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002057 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2058 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2059 SkRect tmp(r);
2060 tmp.sort();
2061
Mike Reed822128b2017-02-28 16:41:03 -05002062 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002063 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2064 return;
2065 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002066 }
reed@google.com4b226022011-01-11 18:32:13 +00002067
reed4a167172016-08-18 17:15:25 -07002068 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002069 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002070
reed4a167172016-08-18 17:15:25 -07002071 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002072 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002073 }
2074
2075 LOOPER_END
2076 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002077 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002078 SkDrawIter iter(this);
2079 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002080 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002081 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002083}
2084
msarett44df6512016-08-25 13:54:30 -07002085void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002086 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002087 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002088 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002089 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2090 return;
2091 }
msarett44df6512016-08-25 13:54:30 -07002092 }
2093
Mike Reed822128b2017-02-28 16:41:03 -05002094 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002095
2096 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002097 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002098 }
2099
2100 LOOPER_END
2101}
2102
reed41af9662015-01-05 07:49:08 -08002103void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002104 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002105 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002106 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002107 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2108 return;
2109 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002110 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002111
Mike Reed822128b2017-02-28 16:41:03 -05002112 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002113
2114 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002115 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002116 }
2117
2118 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002119}
2120
bsalomonac3aa242016-08-19 11:25:19 -07002121void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2122 SkScalar sweepAngle, bool useCenter,
2123 const SkPaint& paint) {
2124 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002125 if (paint.canComputeFastBounds()) {
2126 SkRect storage;
2127 // Note we're using the entire oval as the bounds.
2128 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2129 return;
2130 }
bsalomonac3aa242016-08-19 11:25:19 -07002131 }
2132
Mike Reed822128b2017-02-28 16:41:03 -05002133 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002134
2135 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002136 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002137 }
2138
2139 LOOPER_END
2140}
2141
reed41af9662015-01-05 07:49:08 -08002142void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002143 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002144 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002145 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002146 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2147 return;
2148 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002149 }
2150
2151 if (rrect.isRect()) {
2152 // call the non-virtual version
2153 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002154 return;
2155 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002156 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002157 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2158 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002159 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002160
Mike Reed822128b2017-02-28 16:41:03 -05002161 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002162
2163 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002164 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002165 }
2166
2167 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002168}
2169
Mike Reed822128b2017-02-28 16:41:03 -05002170void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002171 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002172 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002173 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2174 return;
2175 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002176 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002177
Mike Reed822128b2017-02-28 16:41:03 -05002178 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002179
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002180 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002181 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002182 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002183
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002184 LOOPER_END
2185}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002186
reed41af9662015-01-05 07:49:08 -08002187void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002188 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002189 if (!path.isFinite()) {
2190 return;
2191 }
2192
Mike Reed822128b2017-02-28 16:41:03 -05002193 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002194 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002195 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002196 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2197 return;
2198 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002199 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002200
Mike Reed822128b2017-02-28 16:41:03 -05002201 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002202 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002203 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002204 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002205 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002206 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002207
Mike Reed822128b2017-02-28 16:41:03 -05002208 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002209
2210 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002211 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002212 }
2213
reed@google.com4e2b3d32011-04-07 14:18:59 +00002214 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002215}
2216
reed262a71b2015-12-05 13:07:27 -08002217bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002218 if (!paint.getImageFilter()) {
2219 return false;
2220 }
2221
2222 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002223 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002224 return false;
2225 }
2226
2227 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2228 // Once we can filter and the filter will return a result larger than itself, we should be
2229 // able to remove this constraint.
2230 // skbug.com/4526
2231 //
2232 SkPoint pt;
2233 ctm.mapXY(x, y, &pt);
2234 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2235 return ir.contains(fMCRec->fRasterClip.getBounds());
2236}
2237
reeda85d4d02015-05-06 12:56:48 -07002238void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002239 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002240 SkRect bounds = SkRect::MakeXYWH(x, y,
2241 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002242 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002243 SkRect tmp = bounds;
2244 if (paint) {
2245 paint->computeFastBounds(tmp, &tmp);
2246 }
2247 if (this->quickReject(tmp)) {
2248 return;
2249 }
reeda85d4d02015-05-06 12:56:48 -07002250 }
halcanary9d524f22016-03-29 09:03:52 -07002251
reeda85d4d02015-05-06 12:56:48 -07002252 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002253 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002254 paint = lazy.init();
2255 }
reed262a71b2015-12-05 13:07:27 -08002256
reeda2217ef2016-07-20 06:04:34 -07002257 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002258 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2259 *paint);
2260 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002261 special = this->getDevice()->makeSpecial(image);
2262 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002263 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002264 }
2265 }
2266
reed262a71b2015-12-05 13:07:27 -08002267 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2268
reeda85d4d02015-05-06 12:56:48 -07002269 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002270 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002271 if (special) {
2272 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002273 iter.fDevice->ctm().mapXY(x, y, &pt);
2274 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002275 SkScalarRoundToInt(pt.fX),
2276 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002277 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002278 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002279 }
reeda85d4d02015-05-06 12:56:48 -07002280 }
halcanary9d524f22016-03-29 09:03:52 -07002281
reeda85d4d02015-05-06 12:56:48 -07002282 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002283}
2284
reed41af9662015-01-05 07:49:08 -08002285void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002286 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002287 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002288 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002289 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002290 if (paint) {
2291 paint->computeFastBounds(dst, &storage);
2292 }
2293 if (this->quickReject(storage)) {
2294 return;
2295 }
reeda85d4d02015-05-06 12:56:48 -07002296 }
2297 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002298 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002299 paint = lazy.init();
2300 }
halcanary9d524f22016-03-29 09:03:52 -07002301
senorblancoc41e7e12015-12-07 12:51:30 -08002302 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002303 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002304
reeda85d4d02015-05-06 12:56:48 -07002305 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002306 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002307 }
halcanary9d524f22016-03-29 09:03:52 -07002308
reeda85d4d02015-05-06 12:56:48 -07002309 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002310}
2311
reed41af9662015-01-05 07:49:08 -08002312void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002313 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002314 SkDEBUGCODE(bitmap.validate();)
2315
reed33366972015-10-08 09:22:02 -07002316 if (bitmap.drawsNothing()) {
2317 return;
2318 }
2319
2320 SkLazyPaint lazy;
2321 if (nullptr == paint) {
2322 paint = lazy.init();
2323 }
2324
Mike Reed822128b2017-02-28 16:41:03 -05002325 SkRect bounds;
2326 bitmap.getBounds(&bounds);
2327 bounds.offset(x, y);
2328 bool canFastBounds = paint->canComputeFastBounds();
2329 if (canFastBounds) {
2330 SkRect storage;
2331 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002332 return;
2333 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002334 }
reed@google.com4b226022011-01-11 18:32:13 +00002335
reeda2217ef2016-07-20 06:04:34 -07002336 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002337 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2338 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002339 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002340 special = this->getDevice()->makeSpecial(bitmap);
2341 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002342 drawAsSprite = false;
2343 }
2344 }
2345
Mike Reed822128b2017-02-28 16:41:03 -05002346 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2347
2348 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002349
2350 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002351 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002352 if (special) {
reed262a71b2015-12-05 13:07:27 -08002353 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002354 iter.fDevice->ctm().mapXY(x, y, &pt);
2355 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002356 SkScalarRoundToInt(pt.fX),
2357 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002358 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002359 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002360 }
reed33366972015-10-08 09:22:02 -07002361 }
msarettfbfa2582016-08-12 08:29:08 -07002362
reed33366972015-10-08 09:22:02 -07002363 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364}
2365
reed@google.com9987ec32011-09-07 11:57:52 +00002366// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002367void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002368 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002369 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002370 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002371 return;
2372 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002373
halcanary96fcdcc2015-08-27 07:41:13 -07002374 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002375 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002376 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2377 return;
2378 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002379 }
reed@google.com3d608122011-11-21 15:16:16 +00002380
reed@google.com33535f32012-09-25 15:37:50 +00002381 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002382 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002383 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002384 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002385
senorblancoc41e7e12015-12-07 12:51:30 -08002386 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002387 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002388
reed@google.com33535f32012-09-25 15:37:50 +00002389 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002390 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002391 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002392
reed@google.com33535f32012-09-25 15:37:50 +00002393 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002394}
2395
reed41af9662015-01-05 07:49:08 -08002396void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002397 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002398 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002399 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002400 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002401}
2402
reed4c21dc52015-06-25 12:32:03 -07002403void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2404 const SkPaint* paint) {
2405 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002406
halcanary96fcdcc2015-08-27 07:41:13 -07002407 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002408 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002409 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2410 return;
2411 }
reed@google.com3d608122011-11-21 15:16:16 +00002412 }
halcanary9d524f22016-03-29 09:03:52 -07002413
reed4c21dc52015-06-25 12:32:03 -07002414 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002415 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002416 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002417 }
halcanary9d524f22016-03-29 09:03:52 -07002418
senorblancoc41e7e12015-12-07 12:51:30 -08002419 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002420
reed4c21dc52015-06-25 12:32:03 -07002421 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002422 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002423 }
halcanary9d524f22016-03-29 09:03:52 -07002424
reed4c21dc52015-06-25 12:32:03 -07002425 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002426}
2427
reed41af9662015-01-05 07:49:08 -08002428void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2429 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002430 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002431 SkDEBUGCODE(bitmap.validate();)
2432
halcanary96fcdcc2015-08-27 07:41:13 -07002433 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002434 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002435 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2436 return;
2437 }
reed4c21dc52015-06-25 12:32:03 -07002438 }
halcanary9d524f22016-03-29 09:03:52 -07002439
reed4c21dc52015-06-25 12:32:03 -07002440 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002441 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002442 paint = lazy.init();
2443 }
halcanary9d524f22016-03-29 09:03:52 -07002444
senorblancoc41e7e12015-12-07 12:51:30 -08002445 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002446
reed4c21dc52015-06-25 12:32:03 -07002447 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002448 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002449 }
halcanary9d524f22016-03-29 09:03:52 -07002450
reed4c21dc52015-06-25 12:32:03 -07002451 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002452}
2453
msarett16882062016-08-16 09:31:08 -07002454void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2455 const SkPaint* paint) {
2456 if (nullptr == paint || paint->canComputeFastBounds()) {
2457 SkRect storage;
2458 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2459 return;
2460 }
2461 }
2462
2463 SkLazyPaint lazy;
2464 if (nullptr == paint) {
2465 paint = lazy.init();
2466 }
2467
2468 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2469
2470 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002471 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002472 }
2473
2474 LOOPER_END
2475}
2476
2477void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2478 const SkRect& dst, const SkPaint* paint) {
2479 if (nullptr == paint || paint->canComputeFastBounds()) {
2480 SkRect storage;
2481 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2482 return;
2483 }
2484 }
2485
2486 SkLazyPaint lazy;
2487 if (nullptr == paint) {
2488 paint = lazy.init();
2489 }
2490
2491 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2492
2493 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002494 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002495 }
2496
2497 LOOPER_END
2498}
2499
reed@google.comf67e4cf2011-03-15 20:56:58 +00002500class SkDeviceFilteredPaint {
2501public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002502 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002503 uint32_t filteredFlags = device->filterTextFlags(paint);
2504 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002505 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002506 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002507 fPaint = newPaint;
2508 } else {
2509 fPaint = &paint;
2510 }
2511 }
2512
reed@google.comf67e4cf2011-03-15 20:56:58 +00002513 const SkPaint& paint() const { return *fPaint; }
2514
2515private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002516 const SkPaint* fPaint;
2517 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002518};
2519
reed@google.come0d9ce82014-04-23 04:00:17 +00002520void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2521 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002522 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002523
2524 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002525 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002526 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002527 }
2528
reed@google.com4e2b3d32011-04-07 14:18:59 +00002529 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002530}
2531
reed@google.come0d9ce82014-04-23 04:00:17 +00002532void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2533 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002534 SkPoint textOffset = SkPoint::Make(0, 0);
2535
halcanary96fcdcc2015-08-27 07:41:13 -07002536 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002537
reed@android.com8a1c16f2008-12-17 15:59:43 +00002538 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002539 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002540 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002541 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002542 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002543
reed@google.com4e2b3d32011-04-07 14:18:59 +00002544 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002545}
2546
reed@google.come0d9ce82014-04-23 04:00:17 +00002547void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2548 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002549
2550 SkPoint textOffset = SkPoint::Make(0, constY);
2551
halcanary96fcdcc2015-08-27 07:41:13 -07002552 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002553
reed@android.com8a1c16f2008-12-17 15:59:43 +00002554 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002555 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002556 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002557 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002558 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002559
reed@google.com4e2b3d32011-04-07 14:18:59 +00002560 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002561}
2562
reed@google.come0d9ce82014-04-23 04:00:17 +00002563void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2564 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002565 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002566
reed@android.com8a1c16f2008-12-17 15:59:43 +00002567 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002568 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002569 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002570 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002571
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002572 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002573}
2574
reed45561a02016-07-07 12:47:17 -07002575void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2576 const SkRect* cullRect, const SkPaint& paint) {
2577 if (cullRect && this->quickReject(*cullRect)) {
2578 return;
2579 }
2580
2581 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2582
2583 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002584 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002585 }
2586
2587 LOOPER_END
2588}
2589
fmalita00d5c2c2014-08-21 08:53:26 -07002590void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2591 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002592
fmalita85d5eb92015-03-04 11:20:12 -08002593 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002594 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002595 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002596 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002597 SkRect tmp;
2598 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2599 return;
2600 }
2601 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002602 }
2603
fmalita024f9962015-03-03 19:08:17 -08002604 // We cannot filter in the looper as we normally do, because the paint is
2605 // incomplete at this point (text-related attributes are embedded within blob run paints).
2606 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002607 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002608
fmalita85d5eb92015-03-04 11:20:12 -08002609 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002610
fmalitaaa1b9122014-08-28 14:32:24 -07002611 while (iter.next()) {
2612 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002613 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002614 }
2615
fmalitaaa1b9122014-08-28 14:32:24 -07002616 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002617
2618 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002619}
2620
reed@google.come0d9ce82014-04-23 04:00:17 +00002621// These will become non-virtual, so they always call the (virtual) onDraw... method
2622void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2623 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002624 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002625 if (byteLength) {
2626 this->onDrawText(text, byteLength, x, y, paint);
2627 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002628}
2629void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2630 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002631 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002632 if (byteLength) {
2633 this->onDrawPosText(text, byteLength, pos, paint);
2634 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002635}
2636void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2637 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002638 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002639 if (byteLength) {
2640 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2641 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002642}
2643void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2644 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002645 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002646 if (byteLength) {
2647 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2648 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002649}
reed45561a02016-07-07 12:47:17 -07002650void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2651 const SkRect* cullRect, const SkPaint& paint) {
2652 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2653 if (byteLength) {
2654 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2655 }
2656}
fmalita00d5c2c2014-08-21 08:53:26 -07002657void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2658 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002659 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002660 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002661 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002662}
reed@google.come0d9ce82014-04-23 04:00:17 +00002663
Mike Reede88a1cb2017-03-17 09:50:46 -04002664void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2665 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002666 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2667 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2668
2669 while (iter.next()) {
2670 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002671 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002672 }
2673
2674 LOOPER_END
2675}
2676
dandovb3c9d1c2014-08-12 08:34:29 -07002677void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002678 const SkPoint texCoords[4], SkBlendMode bmode,
2679 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002680 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002681 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002682 return;
2683 }
mtklein6cfa73a2014-08-13 13:33:49 -07002684
Mike Reedfaba3712016-11-03 14:45:31 -04002685 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002686}
2687
2688void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002689 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002690 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002691 // Since a patch is always within the convex hull of the control points, we discard it when its
2692 // bounding rectangle is completely outside the current clip.
2693 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002694 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002695 if (this->quickReject(bounds)) {
2696 return;
2697 }
mtklein6cfa73a2014-08-13 13:33:49 -07002698
halcanary96fcdcc2015-08-27 07:41:13 -07002699 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002700
dandovecfff212014-08-04 10:02:00 -07002701 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002702 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002703 }
mtklein6cfa73a2014-08-13 13:33:49 -07002704
dandovecfff212014-08-04 10:02:00 -07002705 LOOPER_END
2706}
2707
reeda8db7282015-07-07 10:22:31 -07002708void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002709 RETURN_ON_NULL(dr);
2710 if (x || y) {
2711 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2712 this->onDrawDrawable(dr, &matrix);
2713 } else {
2714 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002715 }
2716}
2717
reeda8db7282015-07-07 10:22:31 -07002718void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002719 RETURN_ON_NULL(dr);
2720 if (matrix && matrix->isIdentity()) {
2721 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002722 }
reede3b38ce2016-01-08 09:18:44 -08002723 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002724}
2725
2726void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002727 // drawable bounds are no longer reliable (e.g. android displaylist)
2728 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002729 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002730}
2731
reed71c3c762015-06-24 10:29:17 -07002732void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002733 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002734 const SkRect* cull, const SkPaint* paint) {
2735 if (cull && this->quickReject(*cull)) {
2736 return;
2737 }
2738
2739 SkPaint pnt;
2740 if (paint) {
2741 pnt = *paint;
2742 }
halcanary9d524f22016-03-29 09:03:52 -07002743
halcanary96fcdcc2015-08-27 07:41:13 -07002744 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002745 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002746 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002747 }
2748 LOOPER_END
2749}
2750
reedf70b5312016-03-04 16:36:20 -08002751void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2752 SkASSERT(key);
2753
2754 SkPaint paint;
2755 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2756 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002757 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002758 }
2759 LOOPER_END
2760}
2761
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762//////////////////////////////////////////////////////////////////////////////
2763// These methods are NOT virtual, and therefore must call back into virtual
2764// methods, rather than actually drawing themselves.
2765//////////////////////////////////////////////////////////////////////////////
2766
Mike Reed3661bc92017-02-22 13:21:42 -05002767#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed374772b2016-10-05 17:33:02 -07002768void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002769 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 SkPaint paint;
2771
2772 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002773 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774 this->drawPaint(paint);
2775}
Mike Reed3661bc92017-02-22 13:21:42 -05002776#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777
reed374772b2016-10-05 17:33:02 -07002778void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002779 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780 SkPaint paint;
2781
2782 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002783 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784 this->drawPaint(paint);
2785}
2786
2787void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002788 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002789 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2791}
2792
Mike Reed3661bc92017-02-22 13:21:42 -05002793#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002795 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796 SkPoint pt;
2797 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002798
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799 pt.set(x, y);
2800 paint.setColor(color);
2801 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2802}
Mike Reed3661bc92017-02-22 13:21:42 -05002803#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002804
Mike Reed3661bc92017-02-22 13:21:42 -05002805void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002806 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002808
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809 pts[0].set(x0, y0);
2810 pts[1].set(x1, y1);
2811 this->drawPoints(kLines_PointMode, 2, pts, paint);
2812}
2813
Mike Reed3661bc92017-02-22 13:21:42 -05002814#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002815void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2816 SkScalar right, SkScalar bottom,
2817 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002818 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002819 SkRect r;
2820
2821 r.set(left, top, right, bottom);
2822 this->drawRect(r, paint);
2823}
Mike Reed3661bc92017-02-22 13:21:42 -05002824#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825
Mike Reed3661bc92017-02-22 13:21:42 -05002826void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002827 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828 if (radius < 0) {
2829 radius = 0;
2830 }
2831
2832 SkRect r;
2833 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002834 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002835}
2836
2837void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2838 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002839 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002841 SkRRect rrect;
2842 rrect.setRectXY(r, rx, ry);
2843 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002844 } else {
2845 this->drawRect(r, paint);
2846 }
2847}
2848
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2850 SkScalar sweepAngle, bool useCenter,
2851 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002852 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002853 if (oval.isEmpty() || !sweepAngle) {
2854 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002855 }
bsalomon21af9ca2016-08-25 12:29:23 -07002856 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002857}
2858
2859void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2860 const SkPath& path, SkScalar hOffset,
2861 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002862 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002863 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002864
reed@android.com8a1c16f2008-12-17 15:59:43 +00002865 matrix.setTranslate(hOffset, vOffset);
2866 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2867}
2868
reed@android.comf76bacf2009-05-13 14:00:33 +00002869///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002870
2871/**
2872 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2873 * against the playback cost of recursing into the subpicture to get at its actual ops.
2874 *
2875 * For now we pick a conservatively small value, though measurement (and other heuristics like
2876 * the type of ops contained) may justify changing this value.
2877 */
2878#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002879
reedd5fa1a42014-08-09 11:08:05 -07002880void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002881 RETURN_ON_NULL(picture);
2882
reed1c2c4412015-04-30 13:09:24 -07002883 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002884 if (matrix && matrix->isIdentity()) {
2885 matrix = nullptr;
2886 }
2887 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2888 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2889 picture->playback(this);
2890 } else {
2891 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002892 }
2893}
robertphillips9b14f262014-06-04 05:40:44 -07002894
reedd5fa1a42014-08-09 11:08:05 -07002895void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2896 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002897 if (!paint || paint->canComputeFastBounds()) {
2898 SkRect bounds = picture->cullRect();
2899 if (paint) {
2900 paint->computeFastBounds(bounds, &bounds);
2901 }
2902 if (matrix) {
2903 matrix->mapRect(&bounds);
2904 }
2905 if (this->quickReject(bounds)) {
2906 return;
2907 }
2908 }
2909
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002910 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002911 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002912}
2913
vjiaoblack95302da2016-07-21 10:25:54 -07002914#ifdef SK_EXPERIMENTAL_SHADOWING
2915void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2916 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002917 const SkPaint* paint,
2918 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002919 RETURN_ON_NULL(picture);
2920
2921 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2922
vjiaoblacke6f5d562016-08-25 06:30:23 -07002923 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002924}
2925
2926void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2927 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002928 const SkPaint* paint,
2929 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002930 if (!paint || paint->canComputeFastBounds()) {
2931 SkRect bounds = picture->cullRect();
2932 if (paint) {
2933 paint->computeFastBounds(bounds, &bounds);
2934 }
2935 if (matrix) {
2936 matrix->mapRect(&bounds);
2937 }
2938 if (this->quickReject(bounds)) {
2939 return;
2940 }
2941 }
2942
2943 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2944
vjiaoblacke6f5d562016-08-25 06:30:23 -07002945 sk_sp<SkImage> povDepthMap;
2946 sk_sp<SkImage> diffuseMap;
2947
vjiaoblack904527d2016-08-09 09:32:09 -07002948 // povDepthMap
2949 {
2950 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002951 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2952 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002953 sk_sp<SkLights> povLight = builder.finish();
2954
2955 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2956 picture->cullRect().height(),
2957 kBGRA_8888_SkColorType,
2958 kOpaque_SkAlphaType);
2959
2960 // Create a new surface (that matches the backend of canvas)
2961 // to create the povDepthMap
2962 sk_sp<SkSurface> surf(this->makeSurface(info));
2963
2964 // Wrap another SPFCanvas around the surface
2965 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2966 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2967
2968 // set the depth map canvas to have the light as the user's POV
2969 depthMapCanvas->setLights(std::move(povLight));
2970
2971 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002972 povDepthMap = surf->makeImageSnapshot();
2973 }
2974
2975 // diffuseMap
2976 {
2977 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2978 picture->cullRect().height(),
2979 kBGRA_8888_SkColorType,
2980 kOpaque_SkAlphaType);
2981
2982 sk_sp<SkSurface> surf(this->makeSurface(info));
2983 surf->getCanvas()->drawPicture(picture);
2984
2985 diffuseMap = surf->makeImageSnapshot();
2986 }
vjiaoblack904527d2016-08-09 09:32:09 -07002987
2988 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
2989 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07002990 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
2991 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07002992
2993 // TODO: pass the depth to the shader in vertices, or uniforms
2994 // so we don't have to render depth and color separately
2995 for (int i = 0; i < fLights->numLights(); ++i) {
2996 // skip over ambient lights; they don't cast shadows
2997 // lights that have shadow maps do not need updating (because lights are immutable)
2998 sk_sp<SkImage> depthMap;
2999 SkISize shMapSize;
3000
3001 if (fLights->light(i).getShadowMap() != nullptr) {
3002 continue;
3003 }
3004
3005 if (fLights->light(i).isRadial()) {
3006 shMapSize.fHeight = 1;
3007 shMapSize.fWidth = (int) picture->cullRect().width();
3008
3009 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3010 kBGRA_8888_SkColorType,
3011 kOpaque_SkAlphaType);
3012
3013 // Create new surface (that matches the backend of canvas)
3014 // for each shadow map
3015 sk_sp<SkSurface> surf(this->makeSurface(info));
3016
3017 // Wrap another SPFCanvas around the surface
3018 SkCanvas* depthMapCanvas = surf->getCanvas();
3019
3020 SkLights::Builder builder;
3021 builder.add(fLights->light(i));
3022 sk_sp<SkLights> curLight = builder.finish();
3023
3024 sk_sp<SkShader> shadowMapShader;
3025 shadowMapShader = SkRadialShadowMapShader::Make(
3026 povDepthShader, curLight,
3027 (int) picture->cullRect().width(),
3028 (int) picture->cullRect().height());
3029
3030 SkPaint shadowMapPaint;
3031 shadowMapPaint.setShader(std::move(shadowMapShader));
3032
3033 depthMapCanvas->setLights(curLight);
3034
3035 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3036 diffuseMap->height()),
3037 shadowMapPaint);
3038
3039 depthMap = surf->makeImageSnapshot();
3040
3041 } else {
3042 // TODO: compute the correct size of the depth map from the light properties
3043 // TODO: maybe add a kDepth_8_SkColorType
3044 // TODO: find actual max depth of picture
3045 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3046 fLights->light(i), 255,
3047 (int) picture->cullRect().width(),
3048 (int) picture->cullRect().height());
3049
3050 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3051 kBGRA_8888_SkColorType,
3052 kOpaque_SkAlphaType);
3053
3054 // Create a new surface (that matches the backend of canvas)
3055 // for each shadow map
3056 sk_sp<SkSurface> surf(this->makeSurface(info));
3057
3058 // Wrap another SPFCanvas around the surface
3059 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3060 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3061 depthMapCanvas->setShadowParams(params);
3062
3063 // set the depth map canvas to have the light we're drawing.
3064 SkLights::Builder builder;
3065 builder.add(fLights->light(i));
3066 sk_sp<SkLights> curLight = builder.finish();
3067 depthMapCanvas->setLights(std::move(curLight));
3068
3069 depthMapCanvas->drawPicture(picture);
3070 depthMap = surf->makeImageSnapshot();
3071 }
3072
3073 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3074 fLights->light(i).setShadowMap(std::move(depthMap));
3075 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3076 // we blur the variance map
3077 SkPaint blurPaint;
3078 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3079 params.fShadowRadius, nullptr));
3080
3081 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3082 kBGRA_8888_SkColorType,
3083 kOpaque_SkAlphaType);
3084
3085 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3086
3087 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3088
3089 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3090 }
3091 }
3092
3093 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003094 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3095 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003096 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003097 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003098 diffuseMap->height(),
3099 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003100
3101 shadowPaint.setShader(shadowShader);
3102
3103 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003104}
3105#endif
3106
reed@android.com8a1c16f2008-12-17 15:59:43 +00003107///////////////////////////////////////////////////////////////////////////////
3108///////////////////////////////////////////////////////////////////////////////
3109
reed3aafe112016-08-18 12:45:34 -07003110SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003111 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003112
3113 SkASSERT(canvas);
3114
reed3aafe112016-08-18 12:45:34 -07003115 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003116 fDone = !fImpl->next();
3117}
3118
3119SkCanvas::LayerIter::~LayerIter() {
3120 fImpl->~SkDrawIter();
3121}
3122
3123void SkCanvas::LayerIter::next() {
3124 fDone = !fImpl->next();
3125}
3126
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003127SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003128 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003129}
3130
3131const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003132 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003133}
3134
3135const SkPaint& SkCanvas::LayerIter::paint() const {
3136 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003137 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003138 paint = &fDefaultPaint;
3139 }
3140 return *paint;
3141}
3142
Mike Reeda1361362017-03-07 09:37:29 -05003143void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3144 return fImpl->fDevice->onAsRgnClip(rgn);
3145}
3146
reed@android.com8a1c16f2008-12-17 15:59:43 +00003147int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3148int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003149
3150///////////////////////////////////////////////////////////////////////////////
3151
Mike Reed8310f0e2017-03-08 21:42:37 +00003152SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
3153
3154///////////////////////////////////////////////////////////////////////////////
3155
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003156static bool supported_for_raster_canvas(const SkImageInfo& info) {
3157 switch (info.alphaType()) {
3158 case kPremul_SkAlphaType:
3159 case kOpaque_SkAlphaType:
3160 break;
3161 default:
3162 return false;
3163 }
3164
3165 switch (info.colorType()) {
3166 case kAlpha_8_SkColorType:
3167 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003168 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003169 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003170 break;
3171 default:
3172 return false;
3173 }
3174
3175 return true;
3176}
3177
Mike Reed5df49342016-11-12 08:06:55 -06003178std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3179 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003180 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003181 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003182 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003183
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003184 SkBitmap bitmap;
3185 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003186 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003187 }
Mike Reed5df49342016-11-12 08:06:55 -06003188 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003189}
reedd5fa1a42014-08-09 11:08:05 -07003190
3191///////////////////////////////////////////////////////////////////////////////
3192
3193SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003194 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003195 : fCanvas(canvas)
3196 , fSaveCount(canvas->getSaveCount())
3197{
bsalomon49f085d2014-09-05 13:34:00 -07003198 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003199 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003200 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003201 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003202 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003203 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003204 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003205 canvas->save();
3206 }
mtklein6cfa73a2014-08-13 13:33:49 -07003207
bsalomon49f085d2014-09-05 13:34:00 -07003208 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003209 canvas->concat(*matrix);
3210 }
3211}
3212
3213SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3214 fCanvas->restoreToCount(fSaveCount);
3215}
reede8f30622016-03-23 18:59:25 -07003216
Florin Malitaee424ac2016-12-01 12:47:59 -05003217///////////////////////////////////////////////////////////////////////////////
3218
3219SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3220 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3221
Florin Malita439ace92016-12-02 12:05:41 -05003222SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3223 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3224
Florin Malitaee424ac2016-12-01 12:47:59 -05003225SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3226 (void)this->INHERITED::getSaveLayerStrategy(rec);
3227 return kNoLayer_SaveLayerStrategy;
3228}
3229
3230///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003231
reed73603f32016-09-20 08:42:38 -07003232static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3233static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3234static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3235static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3236static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3237static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003238
3239///////////////////////////////////////////////////////////////////////////////////////////////////
3240
3241SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3242 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3243 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3244 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3245 SkIPoint origin = dev->getOrigin();
3246 SkMatrix ctm = this->getTotalMatrix();
3247 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3248
3249 SkIRect clip = fMCRec->fRasterClip.getBounds();
3250 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003251 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003252 clip.setEmpty();
3253 }
3254
3255 fAllocator->updateHandle(handle, ctm, clip);
3256 return handle;
3257 }
3258 return nullptr;
3259}
3260
3261static bool install(SkBitmap* bm, const SkImageInfo& info,
3262 const SkRasterHandleAllocator::Rec& rec) {
3263 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3264 rec.fReleaseProc, rec.fReleaseCtx);
3265}
3266
3267SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3268 SkBitmap* bm) {
3269 SkRasterHandleAllocator::Rec rec;
3270 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3271 return nullptr;
3272 }
3273 return rec.fHandle;
3274}
3275
3276std::unique_ptr<SkCanvas>
3277SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3278 const SkImageInfo& info, const Rec* rec) {
3279 if (!alloc || !supported_for_raster_canvas(info)) {
3280 return nullptr;
3281 }
3282
3283 SkBitmap bm;
3284 Handle hndl;
3285
3286 if (rec) {
3287 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3288 } else {
3289 hndl = alloc->allocBitmap(info, &bm);
3290 }
3291 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3292}