blob: 030180475d9298360af9b013ed8ba11628e2baac [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 Reed02be3c12017-03-23 12:34:15 -04001613 return fMCRec->fRasterClip.isEmpty();
1614
1615 // TODO: should we only use the conservative answer in a recording canvas?
1616#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001617 SkBaseDevice* dev = this->getTopDevice();
1618 // if no device we return true
1619 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001620#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001621}
1622
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001623bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001624 SkBaseDevice* dev = this->getTopDevice();
1625 // if no device we return false
1626 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001627}
1628
msarettfbfa2582016-08-12 08:29:08 -07001629static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1630#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1631 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1632 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1633 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1634 return 0xF != _mm_movemask_ps(mask);
1635#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1636 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1637 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1638 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1639 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1640#else
1641 SkRect devRectAsRect;
1642 SkRect devClipAsRect;
1643 devRect.store(&devRectAsRect.fLeft);
1644 devClip.store(&devClipAsRect.fLeft);
1645 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1646#endif
1647}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001648
msarettfbfa2582016-08-12 08:29:08 -07001649// It's important for this function to not be inlined. Otherwise the compiler will share code
1650// between the fast path and the slow path, resulting in two slow paths.
1651static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1652 const SkMatrix& matrix) {
1653 SkRect deviceRect;
1654 matrix.mapRect(&deviceRect, src);
1655 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1656}
1657
1658bool SkCanvas::quickReject(const SkRect& src) const {
1659#ifdef SK_DEBUG
1660 // Verify that fDeviceClipBounds are set properly.
1661 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001662 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001663 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001664 } else {
msarettfbfa2582016-08-12 08:29:08 -07001665 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001666 }
msarettfbfa2582016-08-12 08:29:08 -07001667
msarett9637ea92016-08-18 14:03:30 -07001668 // Verify that fIsScaleTranslate is set properly.
1669 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001670#endif
1671
msarett9637ea92016-08-18 14:03:30 -07001672 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001673 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1674 }
1675
1676 // We inline the implementation of mapScaleTranslate() for the fast path.
1677 float sx = fMCRec->fMatrix.getScaleX();
1678 float sy = fMCRec->fMatrix.getScaleY();
1679 float tx = fMCRec->fMatrix.getTranslateX();
1680 float ty = fMCRec->fMatrix.getTranslateY();
1681 Sk4f scale(sx, sy, sx, sy);
1682 Sk4f trans(tx, ty, tx, ty);
1683
1684 // Apply matrix.
1685 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1686
1687 // Make sure left < right, top < bottom.
1688 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1689 Sk4f min = Sk4f::Min(ltrb, rblt);
1690 Sk4f max = Sk4f::Max(ltrb, rblt);
1691 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1692 // ARM this sequence generates the fastest (a single instruction).
1693 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1694
1695 // Check if the device rect is NaN or outside the clip.
1696 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001697}
1698
reed@google.com3b3e8952012-08-16 20:53:31 +00001699bool SkCanvas::quickReject(const SkPath& path) const {
1700 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001701}
1702
Mike Reed42e8c532017-01-23 14:09:13 -05001703SkRect SkCanvas::onGetLocalClipBounds() const {
1704 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001705 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001706 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001707 }
1708
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001709 SkMatrix inverse;
1710 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001711 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001712 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001713 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714
Mike Reed42e8c532017-01-23 14:09:13 -05001715 SkRect bounds;
1716 SkRect r;
1717 // adjust it outwards in case we are antialiasing
1718 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001719
Mike Reed42e8c532017-01-23 14:09:13 -05001720 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1721 ibounds.fRight + inset, ibounds.fBottom + inset);
1722 inverse.mapRect(&bounds, r);
1723 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001724}
1725
Mike Reed42e8c532017-01-23 14:09:13 -05001726SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001727 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001728}
1729
reed@android.com8a1c16f2008-12-17 15:59:43 +00001730const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001731 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001732}
1733
Brian Osman11052242016-10-27 14:47:55 -04001734GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001735 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001736 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001737}
1738
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001739GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001740 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001741 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001742}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001743
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001744void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1745 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001746 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001747 if (outer.isEmpty()) {
1748 return;
1749 }
1750 if (inner.isEmpty()) {
1751 this->drawRRect(outer, paint);
1752 return;
1753 }
1754
1755 // We don't have this method (yet), but technically this is what we should
1756 // be able to assert...
1757 // SkASSERT(outer.contains(inner));
1758 //
1759 // For now at least check for containment of bounds
1760 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1761
1762 this->onDrawDRRect(outer, inner, paint);
1763}
1764
reed41af9662015-01-05 07:49:08 -08001765// These need to stop being virtual -- clients need to override the onDraw... versions
1766
1767void SkCanvas::drawPaint(const SkPaint& paint) {
1768 this->onDrawPaint(paint);
1769}
1770
1771void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1772 this->onDrawRect(r, paint);
1773}
1774
msarettdca352e2016-08-26 06:37:45 -07001775void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1776 if (region.isEmpty()) {
1777 return;
1778 }
1779
1780 if (region.isRect()) {
1781 return this->drawIRect(region.getBounds(), paint);
1782 }
1783
1784 this->onDrawRegion(region, paint);
1785}
1786
reed41af9662015-01-05 07:49:08 -08001787void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1788 this->onDrawOval(r, paint);
1789}
1790
1791void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1792 this->onDrawRRect(rrect, paint);
1793}
1794
1795void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1796 this->onDrawPoints(mode, count, pts, paint);
1797}
1798
Mike Reedfed9cfd2017-03-17 12:09:04 -04001799void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint positions[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001800 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001801 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reedfed9cfd2017-03-17 12:09:04 -04001802 auto vertices = SkVertices::MakeCopy(vmode, vertexCount, positions, texs, colors,
1803 indexCount, indices);
1804 if (vertices) {
1805 this->onDrawVerticesObject(vertices.get(), bmode, paint);
1806 }
Brian Salomon199fb872017-02-06 09:41:10 -05001807}
1808
Mike Reede88a1cb2017-03-17 09:50:46 -04001809void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1810 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001811 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001812 this->onDrawVerticesObject(vertices.get(), mode, paint);
1813}
1814
1815void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1816 RETURN_ON_NULL(vertices);
1817 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001818}
1819
1820void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1821 this->onDrawPath(path, paint);
1822}
1823
reeda85d4d02015-05-06 12:56:48 -07001824void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001825 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001826 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001827}
1828
reede47829b2015-08-06 10:02:53 -07001829void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1830 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001831 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001832 if (dst.isEmpty() || src.isEmpty()) {
1833 return;
1834 }
1835 this->onDrawImageRect(image, &src, dst, paint, constraint);
1836}
reed41af9662015-01-05 07:49:08 -08001837
reed84984ef2015-07-17 07:09:43 -07001838void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1839 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001840 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001841 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001842}
1843
reede47829b2015-08-06 10:02:53 -07001844void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1845 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001846 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001847 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1848 constraint);
1849}
reede47829b2015-08-06 10:02:53 -07001850
reed4c21dc52015-06-25 12:32:03 -07001851void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1852 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001853 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001854 if (dst.isEmpty()) {
1855 return;
1856 }
msarett552bca92016-08-03 06:53:26 -07001857 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1858 this->onDrawImageNine(image, center, dst, paint);
1859 } else {
reede47829b2015-08-06 10:02:53 -07001860 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001861 }
reed4c21dc52015-06-25 12:32:03 -07001862}
1863
msarett16882062016-08-16 09:31:08 -07001864void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1865 const SkPaint* paint) {
1866 RETURN_ON_NULL(image);
1867 if (dst.isEmpty()) {
1868 return;
1869 }
msarett71df2d72016-09-30 12:41:42 -07001870
1871 SkIRect bounds;
1872 Lattice latticePlusBounds = lattice;
1873 if (!latticePlusBounds.fBounds) {
1874 bounds = SkIRect::MakeWH(image->width(), image->height());
1875 latticePlusBounds.fBounds = &bounds;
1876 }
1877
1878 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1879 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001880 } else {
1881 this->drawImageRect(image, dst, paint);
1882 }
1883}
1884
reed41af9662015-01-05 07:49:08 -08001885void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001886 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001887 return;
1888 }
reed41af9662015-01-05 07:49:08 -08001889 this->onDrawBitmap(bitmap, dx, dy, paint);
1890}
1891
reede47829b2015-08-06 10:02:53 -07001892void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001893 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001894 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001895 return;
1896 }
reede47829b2015-08-06 10:02:53 -07001897 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001898}
1899
reed84984ef2015-07-17 07:09:43 -07001900void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1901 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001902 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001903}
1904
reede47829b2015-08-06 10:02:53 -07001905void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1906 SrcRectConstraint constraint) {
1907 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1908 constraint);
1909}
reede47829b2015-08-06 10:02:53 -07001910
reed41af9662015-01-05 07:49:08 -08001911void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1912 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001913 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001914 return;
1915 }
msarett552bca92016-08-03 06:53:26 -07001916 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1917 this->onDrawBitmapNine(bitmap, center, dst, paint);
1918 } else {
reeda5517e22015-07-14 10:54:12 -07001919 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001920 }
reed41af9662015-01-05 07:49:08 -08001921}
1922
msarettc573a402016-08-02 08:05:56 -07001923void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1924 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001925 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001926 return;
1927 }
msarett71df2d72016-09-30 12:41:42 -07001928
1929 SkIRect bounds;
1930 Lattice latticePlusBounds = lattice;
1931 if (!latticePlusBounds.fBounds) {
1932 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1933 latticePlusBounds.fBounds = &bounds;
1934 }
1935
1936 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1937 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001938 } else {
msarett16882062016-08-16 09:31:08 -07001939 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001940 }
msarettc573a402016-08-02 08:05:56 -07001941}
1942
reed71c3c762015-06-24 10:29:17 -07001943void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001944 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001945 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001946 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001947 if (count <= 0) {
1948 return;
1949 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001950 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001951 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001952 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001953}
1954
reedf70b5312016-03-04 16:36:20 -08001955void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1956 if (key) {
1957 this->onDrawAnnotation(rect, key, value);
1958 }
1959}
1960
reede47829b2015-08-06 10:02:53 -07001961void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1962 const SkPaint* paint, SrcRectConstraint constraint) {
1963 if (src) {
1964 this->drawImageRect(image, *src, dst, paint, constraint);
1965 } else {
1966 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1967 dst, paint, constraint);
1968 }
1969}
1970void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1971 const SkPaint* paint, SrcRectConstraint constraint) {
1972 if (src) {
1973 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1974 } else {
1975 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1976 dst, paint, constraint);
1977 }
1978}
1979
tomhudsoncb3bd182016-05-18 07:24:16 -07001980void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1981 SkIRect layer_bounds = this->getTopLayerBounds();
1982 if (matrix) {
1983 *matrix = this->getTotalMatrix();
1984 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1985 }
1986 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001987 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001988 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1989 }
1990}
1991
reed@android.com8a1c16f2008-12-17 15:59:43 +00001992//////////////////////////////////////////////////////////////////////////////
1993// These are the virtual drawing methods
1994//////////////////////////////////////////////////////////////////////////////
1995
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001996void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001997 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001998 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1999 }
2000}
2001
reed41af9662015-01-05 07:49:08 -08002002void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002003 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002004 this->internalDrawPaint(paint);
2005}
2006
2007void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002008 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002009
2010 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002011 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002012 }
2013
reed@google.com4e2b3d32011-04-07 14:18:59 +00002014 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002015}
2016
reed41af9662015-01-05 07:49:08 -08002017void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2018 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002019 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002020 if ((long)count <= 0) {
2021 return;
2022 }
2023
Mike Reed822128b2017-02-28 16:41:03 -05002024 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002025 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002026 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002027 // special-case 2 points (common for drawing a single line)
2028 if (2 == count) {
2029 r.set(pts[0], pts[1]);
2030 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002031 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002032 }
Mike Reed822128b2017-02-28 16:41:03 -05002033 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002034 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2035 return;
2036 }
2037 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002038 }
reed@google.coma584aed2012-05-16 14:06:02 +00002039
halcanary96fcdcc2015-08-27 07:41:13 -07002040 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002041
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002042 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002043
reed@android.com8a1c16f2008-12-17 15:59:43 +00002044 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002045 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002046 }
reed@google.com4b226022011-01-11 18:32:13 +00002047
reed@google.com4e2b3d32011-04-07 14:18:59 +00002048 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002049}
2050
reed4a167172016-08-18 17:15:25 -07002051static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2052 return ((intptr_t)paint.getImageFilter() |
2053#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2054 (intptr_t)canvas->getDrawFilter() |
2055#endif
2056 (intptr_t)paint.getLooper() ) != 0;
2057}
2058
reed41af9662015-01-05 07:49:08 -08002059void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002060 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002061 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002062 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2063 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2064 SkRect tmp(r);
2065 tmp.sort();
2066
Mike Reed822128b2017-02-28 16:41:03 -05002067 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002068 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2069 return;
2070 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002071 }
reed@google.com4b226022011-01-11 18:32:13 +00002072
reed4a167172016-08-18 17:15:25 -07002073 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002074 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002075
reed4a167172016-08-18 17:15:25 -07002076 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002077 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002078 }
2079
2080 LOOPER_END
2081 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002082 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002083 SkDrawIter iter(this);
2084 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002085 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002086 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002087 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002088}
2089
msarett44df6512016-08-25 13:54:30 -07002090void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002091 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002092 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002093 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002094 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2095 return;
2096 }
msarett44df6512016-08-25 13:54:30 -07002097 }
2098
Mike Reed822128b2017-02-28 16:41:03 -05002099 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002100
2101 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002102 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002103 }
2104
2105 LOOPER_END
2106}
2107
reed41af9662015-01-05 07:49:08 -08002108void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002109 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002110 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002111 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002112 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2113 return;
2114 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002115 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002116
Mike Reed822128b2017-02-28 16:41:03 -05002117 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002118
2119 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002120 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002121 }
2122
2123 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002124}
2125
bsalomonac3aa242016-08-19 11:25:19 -07002126void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2127 SkScalar sweepAngle, bool useCenter,
2128 const SkPaint& paint) {
2129 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002130 if (paint.canComputeFastBounds()) {
2131 SkRect storage;
2132 // Note we're using the entire oval as the bounds.
2133 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2134 return;
2135 }
bsalomonac3aa242016-08-19 11:25:19 -07002136 }
2137
Mike Reed822128b2017-02-28 16:41:03 -05002138 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002139
2140 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002141 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002142 }
2143
2144 LOOPER_END
2145}
2146
reed41af9662015-01-05 07:49:08 -08002147void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002148 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002149 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002150 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002151 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2152 return;
2153 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002154 }
2155
2156 if (rrect.isRect()) {
2157 // call the non-virtual version
2158 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002159 return;
2160 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002161 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002162 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2163 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002164 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002165
Mike Reed822128b2017-02-28 16:41:03 -05002166 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002167
2168 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002169 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002170 }
2171
2172 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002173}
2174
Mike Reed822128b2017-02-28 16:41:03 -05002175void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002176 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002177 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002178 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2179 return;
2180 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002181 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002182
Mike Reed822128b2017-02-28 16:41:03 -05002183 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002184
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002185 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002186 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002187 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002188
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002189 LOOPER_END
2190}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002191
reed41af9662015-01-05 07:49:08 -08002192void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002193 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002194 if (!path.isFinite()) {
2195 return;
2196 }
2197
Mike Reed822128b2017-02-28 16:41:03 -05002198 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002199 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002200 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002201 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2202 return;
2203 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002204 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002205
Mike Reed822128b2017-02-28 16:41:03 -05002206 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002207 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002208 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002209 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002210 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002211 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002212
Mike Reed822128b2017-02-28 16:41:03 -05002213 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002214
2215 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002216 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002217 }
2218
reed@google.com4e2b3d32011-04-07 14:18:59 +00002219 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002220}
2221
reed262a71b2015-12-05 13:07:27 -08002222bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002223 if (!paint.getImageFilter()) {
2224 return false;
2225 }
2226
2227 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002228 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002229 return false;
2230 }
2231
2232 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2233 // Once we can filter and the filter will return a result larger than itself, we should be
2234 // able to remove this constraint.
2235 // skbug.com/4526
2236 //
2237 SkPoint pt;
2238 ctm.mapXY(x, y, &pt);
2239 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2240 return ir.contains(fMCRec->fRasterClip.getBounds());
2241}
2242
reeda85d4d02015-05-06 12:56:48 -07002243void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002244 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002245 SkRect bounds = SkRect::MakeXYWH(x, y,
2246 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002247 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002248 SkRect tmp = bounds;
2249 if (paint) {
2250 paint->computeFastBounds(tmp, &tmp);
2251 }
2252 if (this->quickReject(tmp)) {
2253 return;
2254 }
reeda85d4d02015-05-06 12:56:48 -07002255 }
halcanary9d524f22016-03-29 09:03:52 -07002256
reeda85d4d02015-05-06 12:56:48 -07002257 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002258 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002259 paint = lazy.init();
2260 }
reed262a71b2015-12-05 13:07:27 -08002261
reeda2217ef2016-07-20 06:04:34 -07002262 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002263 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2264 *paint);
2265 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002266 special = this->getDevice()->makeSpecial(image);
2267 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002268 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002269 }
2270 }
2271
reed262a71b2015-12-05 13:07:27 -08002272 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2273
reeda85d4d02015-05-06 12:56:48 -07002274 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002275 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002276 if (special) {
2277 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002278 iter.fDevice->ctm().mapXY(x, y, &pt);
2279 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002280 SkScalarRoundToInt(pt.fX),
2281 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002282 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002283 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002284 }
reeda85d4d02015-05-06 12:56:48 -07002285 }
halcanary9d524f22016-03-29 09:03:52 -07002286
reeda85d4d02015-05-06 12:56:48 -07002287 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002288}
2289
reed41af9662015-01-05 07:49:08 -08002290void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002291 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002292 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002293 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002294 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002295 if (paint) {
2296 paint->computeFastBounds(dst, &storage);
2297 }
2298 if (this->quickReject(storage)) {
2299 return;
2300 }
reeda85d4d02015-05-06 12:56:48 -07002301 }
2302 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002303 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002304 paint = lazy.init();
2305 }
halcanary9d524f22016-03-29 09:03:52 -07002306
senorblancoc41e7e12015-12-07 12:51:30 -08002307 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002308 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002309
reeda85d4d02015-05-06 12:56:48 -07002310 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002311 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002312 }
halcanary9d524f22016-03-29 09:03:52 -07002313
reeda85d4d02015-05-06 12:56:48 -07002314 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002315}
2316
reed41af9662015-01-05 07:49:08 -08002317void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002318 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002319 SkDEBUGCODE(bitmap.validate();)
2320
reed33366972015-10-08 09:22:02 -07002321 if (bitmap.drawsNothing()) {
2322 return;
2323 }
2324
2325 SkLazyPaint lazy;
2326 if (nullptr == paint) {
2327 paint = lazy.init();
2328 }
2329
Mike Reed822128b2017-02-28 16:41:03 -05002330 SkRect bounds;
2331 bitmap.getBounds(&bounds);
2332 bounds.offset(x, y);
2333 bool canFastBounds = paint->canComputeFastBounds();
2334 if (canFastBounds) {
2335 SkRect storage;
2336 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002337 return;
2338 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002339 }
reed@google.com4b226022011-01-11 18:32:13 +00002340
reeda2217ef2016-07-20 06:04:34 -07002341 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002342 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2343 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002344 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002345 special = this->getDevice()->makeSpecial(bitmap);
2346 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002347 drawAsSprite = false;
2348 }
2349 }
2350
Mike Reed822128b2017-02-28 16:41:03 -05002351 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2352
2353 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002354
2355 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002356 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002357 if (special) {
reed262a71b2015-12-05 13:07:27 -08002358 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002359 iter.fDevice->ctm().mapXY(x, y, &pt);
2360 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002361 SkScalarRoundToInt(pt.fX),
2362 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002363 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002364 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002365 }
reed33366972015-10-08 09:22:02 -07002366 }
msarettfbfa2582016-08-12 08:29:08 -07002367
reed33366972015-10-08 09:22:02 -07002368 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002369}
2370
reed@google.com9987ec32011-09-07 11:57:52 +00002371// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002372void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002373 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002374 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002375 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002376 return;
2377 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002378
halcanary96fcdcc2015-08-27 07:41:13 -07002379 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002380 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002381 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2382 return;
2383 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002384 }
reed@google.com3d608122011-11-21 15:16:16 +00002385
reed@google.com33535f32012-09-25 15:37:50 +00002386 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002387 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002388 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002389 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002390
senorblancoc41e7e12015-12-07 12:51:30 -08002391 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002392 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002393
reed@google.com33535f32012-09-25 15:37:50 +00002394 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002395 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002396 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002397
reed@google.com33535f32012-09-25 15:37:50 +00002398 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002399}
2400
reed41af9662015-01-05 07:49:08 -08002401void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002402 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002403 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002404 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002405 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002406}
2407
reed4c21dc52015-06-25 12:32:03 -07002408void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2409 const SkPaint* paint) {
2410 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002411
halcanary96fcdcc2015-08-27 07:41:13 -07002412 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002413 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002414 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2415 return;
2416 }
reed@google.com3d608122011-11-21 15:16:16 +00002417 }
halcanary9d524f22016-03-29 09:03:52 -07002418
reed4c21dc52015-06-25 12:32:03 -07002419 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002420 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002421 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002422 }
halcanary9d524f22016-03-29 09:03:52 -07002423
senorblancoc41e7e12015-12-07 12:51:30 -08002424 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002425
reed4c21dc52015-06-25 12:32:03 -07002426 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002427 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002428 }
halcanary9d524f22016-03-29 09:03:52 -07002429
reed4c21dc52015-06-25 12:32:03 -07002430 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002431}
2432
reed41af9662015-01-05 07:49:08 -08002433void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2434 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002435 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002436 SkDEBUGCODE(bitmap.validate();)
2437
halcanary96fcdcc2015-08-27 07:41:13 -07002438 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002439 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002440 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2441 return;
2442 }
reed4c21dc52015-06-25 12:32:03 -07002443 }
halcanary9d524f22016-03-29 09:03:52 -07002444
reed4c21dc52015-06-25 12:32:03 -07002445 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002446 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002447 paint = lazy.init();
2448 }
halcanary9d524f22016-03-29 09:03:52 -07002449
senorblancoc41e7e12015-12-07 12:51:30 -08002450 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002451
reed4c21dc52015-06-25 12:32:03 -07002452 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002453 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002454 }
halcanary9d524f22016-03-29 09:03:52 -07002455
reed4c21dc52015-06-25 12:32:03 -07002456 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002457}
2458
msarett16882062016-08-16 09:31:08 -07002459void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2460 const SkPaint* paint) {
2461 if (nullptr == paint || paint->canComputeFastBounds()) {
2462 SkRect storage;
2463 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2464 return;
2465 }
2466 }
2467
2468 SkLazyPaint lazy;
2469 if (nullptr == paint) {
2470 paint = lazy.init();
2471 }
2472
2473 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2474
2475 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002476 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002477 }
2478
2479 LOOPER_END
2480}
2481
2482void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2483 const SkRect& dst, const SkPaint* paint) {
2484 if (nullptr == paint || paint->canComputeFastBounds()) {
2485 SkRect storage;
2486 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2487 return;
2488 }
2489 }
2490
2491 SkLazyPaint lazy;
2492 if (nullptr == paint) {
2493 paint = lazy.init();
2494 }
2495
2496 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2497
2498 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002499 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002500 }
2501
2502 LOOPER_END
2503}
2504
reed@google.comf67e4cf2011-03-15 20:56:58 +00002505class SkDeviceFilteredPaint {
2506public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002507 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002508 uint32_t filteredFlags = device->filterTextFlags(paint);
2509 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002510 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002511 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002512 fPaint = newPaint;
2513 } else {
2514 fPaint = &paint;
2515 }
2516 }
2517
reed@google.comf67e4cf2011-03-15 20:56:58 +00002518 const SkPaint& paint() const { return *fPaint; }
2519
2520private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002521 const SkPaint* fPaint;
2522 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002523};
2524
reed@google.come0d9ce82014-04-23 04:00:17 +00002525void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2526 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002527 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002528
2529 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002530 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002531 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002532 }
2533
reed@google.com4e2b3d32011-04-07 14:18:59 +00002534 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002535}
2536
reed@google.come0d9ce82014-04-23 04:00:17 +00002537void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2538 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002539 SkPoint textOffset = SkPoint::Make(0, 0);
2540
halcanary96fcdcc2015-08-27 07:41:13 -07002541 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002542
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002544 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002545 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002546 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002547 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002548
reed@google.com4e2b3d32011-04-07 14:18:59 +00002549 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002550}
2551
reed@google.come0d9ce82014-04-23 04:00:17 +00002552void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2553 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002554
2555 SkPoint textOffset = SkPoint::Make(0, constY);
2556
halcanary96fcdcc2015-08-27 07:41:13 -07002557 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002558
reed@android.com8a1c16f2008-12-17 15:59:43 +00002559 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002560 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002561 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002562 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002563 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002564
reed@google.com4e2b3d32011-04-07 14:18:59 +00002565 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002566}
2567
reed@google.come0d9ce82014-04-23 04:00:17 +00002568void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2569 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002570 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002571
reed@android.com8a1c16f2008-12-17 15:59:43 +00002572 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002573 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002574 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002575 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002576
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002577 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002578}
2579
reed45561a02016-07-07 12:47:17 -07002580void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2581 const SkRect* cullRect, const SkPaint& paint) {
2582 if (cullRect && this->quickReject(*cullRect)) {
2583 return;
2584 }
2585
2586 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2587
2588 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002589 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002590 }
2591
2592 LOOPER_END
2593}
2594
fmalita00d5c2c2014-08-21 08:53:26 -07002595void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2596 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002597
fmalita85d5eb92015-03-04 11:20:12 -08002598 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002599 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002600 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002601 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002602 SkRect tmp;
2603 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2604 return;
2605 }
2606 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002607 }
2608
fmalita024f9962015-03-03 19:08:17 -08002609 // We cannot filter in the looper as we normally do, because the paint is
2610 // incomplete at this point (text-related attributes are embedded within blob run paints).
2611 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002612 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002613
fmalita85d5eb92015-03-04 11:20:12 -08002614 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002615
fmalitaaa1b9122014-08-28 14:32:24 -07002616 while (iter.next()) {
2617 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002618 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002619 }
2620
fmalitaaa1b9122014-08-28 14:32:24 -07002621 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002622
2623 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002624}
2625
reed@google.come0d9ce82014-04-23 04:00:17 +00002626// These will become non-virtual, so they always call the (virtual) onDraw... method
2627void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2628 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002629 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002630 if (byteLength) {
2631 this->onDrawText(text, byteLength, x, y, paint);
2632 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002633}
2634void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2635 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002636 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002637 if (byteLength) {
2638 this->onDrawPosText(text, byteLength, pos, paint);
2639 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002640}
2641void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2642 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002643 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002644 if (byteLength) {
2645 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2646 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002647}
2648void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2649 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002650 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002651 if (byteLength) {
2652 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2653 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002654}
reed45561a02016-07-07 12:47:17 -07002655void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2656 const SkRect* cullRect, const SkPaint& paint) {
2657 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2658 if (byteLength) {
2659 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2660 }
2661}
fmalita00d5c2c2014-08-21 08:53:26 -07002662void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2663 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002664 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002665 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002666 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002667}
reed@google.come0d9ce82014-04-23 04:00:17 +00002668
Mike Reede88a1cb2017-03-17 09:50:46 -04002669void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2670 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002671 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2672 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2673
2674 while (iter.next()) {
2675 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002676 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002677 }
2678
2679 LOOPER_END
2680}
2681
dandovb3c9d1c2014-08-12 08:34:29 -07002682void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002683 const SkPoint texCoords[4], SkBlendMode bmode,
2684 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002685 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002686 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002687 return;
2688 }
mtklein6cfa73a2014-08-13 13:33:49 -07002689
Mike Reedfaba3712016-11-03 14:45:31 -04002690 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002691}
2692
2693void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002694 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002695 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002696 // Since a patch is always within the convex hull of the control points, we discard it when its
2697 // bounding rectangle is completely outside the current clip.
2698 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002699 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002700 if (this->quickReject(bounds)) {
2701 return;
2702 }
mtklein6cfa73a2014-08-13 13:33:49 -07002703
halcanary96fcdcc2015-08-27 07:41:13 -07002704 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002705
dandovecfff212014-08-04 10:02:00 -07002706 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002707 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002708 }
mtklein6cfa73a2014-08-13 13:33:49 -07002709
dandovecfff212014-08-04 10:02:00 -07002710 LOOPER_END
2711}
2712
reeda8db7282015-07-07 10:22:31 -07002713void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002714 RETURN_ON_NULL(dr);
2715 if (x || y) {
2716 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2717 this->onDrawDrawable(dr, &matrix);
2718 } else {
2719 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002720 }
2721}
2722
reeda8db7282015-07-07 10:22:31 -07002723void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002724 RETURN_ON_NULL(dr);
2725 if (matrix && matrix->isIdentity()) {
2726 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002727 }
reede3b38ce2016-01-08 09:18:44 -08002728 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002729}
2730
2731void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002732 // drawable bounds are no longer reliable (e.g. android displaylist)
2733 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002734 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002735}
2736
reed71c3c762015-06-24 10:29:17 -07002737void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002738 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002739 const SkRect* cull, const SkPaint* paint) {
2740 if (cull && this->quickReject(*cull)) {
2741 return;
2742 }
2743
2744 SkPaint pnt;
2745 if (paint) {
2746 pnt = *paint;
2747 }
halcanary9d524f22016-03-29 09:03:52 -07002748
halcanary96fcdcc2015-08-27 07:41:13 -07002749 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002750 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002751 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002752 }
2753 LOOPER_END
2754}
2755
reedf70b5312016-03-04 16:36:20 -08002756void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2757 SkASSERT(key);
2758
2759 SkPaint paint;
2760 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2761 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002762 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002763 }
2764 LOOPER_END
2765}
2766
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767//////////////////////////////////////////////////////////////////////////////
2768// These methods are NOT virtual, and therefore must call back into virtual
2769// methods, rather than actually drawing themselves.
2770//////////////////////////////////////////////////////////////////////////////
2771
Mike Reed3661bc92017-02-22 13:21:42 -05002772#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed374772b2016-10-05 17:33:02 -07002773void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002774 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775 SkPaint paint;
2776
2777 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002778 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779 this->drawPaint(paint);
2780}
Mike Reed3661bc92017-02-22 13:21:42 -05002781#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782
reed374772b2016-10-05 17:33:02 -07002783void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002784 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002785 SkPaint paint;
2786
2787 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002788 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002789 this->drawPaint(paint);
2790}
2791
2792void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002794 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2796}
2797
Mike Reed3661bc92017-02-22 13:21:42 -05002798#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002800 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002801 SkPoint pt;
2802 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002803
reed@android.com8a1c16f2008-12-17 15:59:43 +00002804 pt.set(x, y);
2805 paint.setColor(color);
2806 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2807}
Mike Reed3661bc92017-02-22 13:21:42 -05002808#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809
Mike Reed3661bc92017-02-22 13:21:42 -05002810void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002811 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002813
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814 pts[0].set(x0, y0);
2815 pts[1].set(x1, y1);
2816 this->drawPoints(kLines_PointMode, 2, pts, paint);
2817}
2818
Mike Reed3661bc92017-02-22 13:21:42 -05002819#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002820void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2821 SkScalar right, SkScalar bottom,
2822 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002823 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002824 SkRect r;
2825
2826 r.set(left, top, right, bottom);
2827 this->drawRect(r, paint);
2828}
Mike Reed3661bc92017-02-22 13:21:42 -05002829#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830
Mike Reed3661bc92017-02-22 13:21:42 -05002831void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002832 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833 if (radius < 0) {
2834 radius = 0;
2835 }
2836
2837 SkRect r;
2838 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002839 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840}
2841
2842void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2843 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002844 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002845 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002846 SkRRect rrect;
2847 rrect.setRectXY(r, rx, ry);
2848 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849 } else {
2850 this->drawRect(r, paint);
2851 }
2852}
2853
reed@android.com8a1c16f2008-12-17 15:59:43 +00002854void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2855 SkScalar sweepAngle, bool useCenter,
2856 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002857 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002858 if (oval.isEmpty() || !sweepAngle) {
2859 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002860 }
bsalomon21af9ca2016-08-25 12:29:23 -07002861 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002862}
2863
2864void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2865 const SkPath& path, SkScalar hOffset,
2866 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002867 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002868 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002869
reed@android.com8a1c16f2008-12-17 15:59:43 +00002870 matrix.setTranslate(hOffset, vOffset);
2871 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2872}
2873
reed@android.comf76bacf2009-05-13 14:00:33 +00002874///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002875
2876/**
2877 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2878 * against the playback cost of recursing into the subpicture to get at its actual ops.
2879 *
2880 * For now we pick a conservatively small value, though measurement (and other heuristics like
2881 * the type of ops contained) may justify changing this value.
2882 */
2883#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002884
reedd5fa1a42014-08-09 11:08:05 -07002885void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002886 RETURN_ON_NULL(picture);
2887
reed1c2c4412015-04-30 13:09:24 -07002888 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002889 if (matrix && matrix->isIdentity()) {
2890 matrix = nullptr;
2891 }
2892 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2893 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2894 picture->playback(this);
2895 } else {
2896 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002897 }
2898}
robertphillips9b14f262014-06-04 05:40:44 -07002899
reedd5fa1a42014-08-09 11:08:05 -07002900void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2901 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002902 if (!paint || paint->canComputeFastBounds()) {
2903 SkRect bounds = picture->cullRect();
2904 if (paint) {
2905 paint->computeFastBounds(bounds, &bounds);
2906 }
2907 if (matrix) {
2908 matrix->mapRect(&bounds);
2909 }
2910 if (this->quickReject(bounds)) {
2911 return;
2912 }
2913 }
2914
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002915 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002916 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002917}
2918
vjiaoblack95302da2016-07-21 10:25:54 -07002919#ifdef SK_EXPERIMENTAL_SHADOWING
2920void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2921 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002922 const SkPaint* paint,
2923 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002924 RETURN_ON_NULL(picture);
2925
2926 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2927
vjiaoblacke6f5d562016-08-25 06:30:23 -07002928 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002929}
2930
2931void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2932 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002933 const SkPaint* paint,
2934 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002935 if (!paint || paint->canComputeFastBounds()) {
2936 SkRect bounds = picture->cullRect();
2937 if (paint) {
2938 paint->computeFastBounds(bounds, &bounds);
2939 }
2940 if (matrix) {
2941 matrix->mapRect(&bounds);
2942 }
2943 if (this->quickReject(bounds)) {
2944 return;
2945 }
2946 }
2947
2948 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2949
vjiaoblacke6f5d562016-08-25 06:30:23 -07002950 sk_sp<SkImage> povDepthMap;
2951 sk_sp<SkImage> diffuseMap;
2952
vjiaoblack904527d2016-08-09 09:32:09 -07002953 // povDepthMap
2954 {
2955 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002956 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2957 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002958 sk_sp<SkLights> povLight = builder.finish();
2959
2960 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2961 picture->cullRect().height(),
2962 kBGRA_8888_SkColorType,
2963 kOpaque_SkAlphaType);
2964
2965 // Create a new surface (that matches the backend of canvas)
2966 // to create the povDepthMap
2967 sk_sp<SkSurface> surf(this->makeSurface(info));
2968
2969 // Wrap another SPFCanvas around the surface
2970 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2971 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2972
2973 // set the depth map canvas to have the light as the user's POV
2974 depthMapCanvas->setLights(std::move(povLight));
2975
2976 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002977 povDepthMap = surf->makeImageSnapshot();
2978 }
2979
2980 // diffuseMap
2981 {
2982 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2983 picture->cullRect().height(),
2984 kBGRA_8888_SkColorType,
2985 kOpaque_SkAlphaType);
2986
2987 sk_sp<SkSurface> surf(this->makeSurface(info));
2988 surf->getCanvas()->drawPicture(picture);
2989
2990 diffuseMap = surf->makeImageSnapshot();
2991 }
vjiaoblack904527d2016-08-09 09:32:09 -07002992
2993 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
2994 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07002995 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
2996 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07002997
2998 // TODO: pass the depth to the shader in vertices, or uniforms
2999 // so we don't have to render depth and color separately
3000 for (int i = 0; i < fLights->numLights(); ++i) {
3001 // skip over ambient lights; they don't cast shadows
3002 // lights that have shadow maps do not need updating (because lights are immutable)
3003 sk_sp<SkImage> depthMap;
3004 SkISize shMapSize;
3005
3006 if (fLights->light(i).getShadowMap() != nullptr) {
3007 continue;
3008 }
3009
3010 if (fLights->light(i).isRadial()) {
3011 shMapSize.fHeight = 1;
3012 shMapSize.fWidth = (int) picture->cullRect().width();
3013
3014 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3015 kBGRA_8888_SkColorType,
3016 kOpaque_SkAlphaType);
3017
3018 // Create new surface (that matches the backend of canvas)
3019 // for each shadow map
3020 sk_sp<SkSurface> surf(this->makeSurface(info));
3021
3022 // Wrap another SPFCanvas around the surface
3023 SkCanvas* depthMapCanvas = surf->getCanvas();
3024
3025 SkLights::Builder builder;
3026 builder.add(fLights->light(i));
3027 sk_sp<SkLights> curLight = builder.finish();
3028
3029 sk_sp<SkShader> shadowMapShader;
3030 shadowMapShader = SkRadialShadowMapShader::Make(
3031 povDepthShader, curLight,
3032 (int) picture->cullRect().width(),
3033 (int) picture->cullRect().height());
3034
3035 SkPaint shadowMapPaint;
3036 shadowMapPaint.setShader(std::move(shadowMapShader));
3037
3038 depthMapCanvas->setLights(curLight);
3039
3040 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3041 diffuseMap->height()),
3042 shadowMapPaint);
3043
3044 depthMap = surf->makeImageSnapshot();
3045
3046 } else {
3047 // TODO: compute the correct size of the depth map from the light properties
3048 // TODO: maybe add a kDepth_8_SkColorType
3049 // TODO: find actual max depth of picture
3050 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3051 fLights->light(i), 255,
3052 (int) picture->cullRect().width(),
3053 (int) picture->cullRect().height());
3054
3055 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3056 kBGRA_8888_SkColorType,
3057 kOpaque_SkAlphaType);
3058
3059 // Create a new surface (that matches the backend of canvas)
3060 // for each shadow map
3061 sk_sp<SkSurface> surf(this->makeSurface(info));
3062
3063 // Wrap another SPFCanvas around the surface
3064 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3065 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3066 depthMapCanvas->setShadowParams(params);
3067
3068 // set the depth map canvas to have the light we're drawing.
3069 SkLights::Builder builder;
3070 builder.add(fLights->light(i));
3071 sk_sp<SkLights> curLight = builder.finish();
3072 depthMapCanvas->setLights(std::move(curLight));
3073
3074 depthMapCanvas->drawPicture(picture);
3075 depthMap = surf->makeImageSnapshot();
3076 }
3077
3078 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3079 fLights->light(i).setShadowMap(std::move(depthMap));
3080 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3081 // we blur the variance map
3082 SkPaint blurPaint;
3083 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3084 params.fShadowRadius, nullptr));
3085
3086 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3087 kBGRA_8888_SkColorType,
3088 kOpaque_SkAlphaType);
3089
3090 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3091
3092 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3093
3094 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3095 }
3096 }
3097
3098 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003099 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3100 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003101 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003102 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003103 diffuseMap->height(),
3104 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003105
3106 shadowPaint.setShader(shadowShader);
3107
3108 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003109}
3110#endif
3111
reed@android.com8a1c16f2008-12-17 15:59:43 +00003112///////////////////////////////////////////////////////////////////////////////
3113///////////////////////////////////////////////////////////////////////////////
3114
reed3aafe112016-08-18 12:45:34 -07003115SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003116 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003117
3118 SkASSERT(canvas);
3119
reed3aafe112016-08-18 12:45:34 -07003120 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003121 fDone = !fImpl->next();
3122}
3123
3124SkCanvas::LayerIter::~LayerIter() {
3125 fImpl->~SkDrawIter();
3126}
3127
3128void SkCanvas::LayerIter::next() {
3129 fDone = !fImpl->next();
3130}
3131
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003132SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003133 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003134}
3135
3136const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003137 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003138}
3139
3140const SkPaint& SkCanvas::LayerIter::paint() const {
3141 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003142 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003143 paint = &fDefaultPaint;
3144 }
3145 return *paint;
3146}
3147
Mike Reeda1361362017-03-07 09:37:29 -05003148void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3149 return fImpl->fDevice->onAsRgnClip(rgn);
3150}
3151
reed@android.com8a1c16f2008-12-17 15:59:43 +00003152int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3153int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003154
3155///////////////////////////////////////////////////////////////////////////////
3156
Mike Reed8310f0e2017-03-08 21:42:37 +00003157SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
3158
3159///////////////////////////////////////////////////////////////////////////////
3160
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003161static bool supported_for_raster_canvas(const SkImageInfo& info) {
3162 switch (info.alphaType()) {
3163 case kPremul_SkAlphaType:
3164 case kOpaque_SkAlphaType:
3165 break;
3166 default:
3167 return false;
3168 }
3169
3170 switch (info.colorType()) {
3171 case kAlpha_8_SkColorType:
3172 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003173 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003174 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003175 break;
3176 default:
3177 return false;
3178 }
3179
3180 return true;
3181}
3182
Mike Reed5df49342016-11-12 08:06:55 -06003183std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3184 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003185 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003186 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003187 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003188
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003189 SkBitmap bitmap;
3190 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003191 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003192 }
Mike Reed5df49342016-11-12 08:06:55 -06003193 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003194}
reedd5fa1a42014-08-09 11:08:05 -07003195
3196///////////////////////////////////////////////////////////////////////////////
3197
3198SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003199 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003200 : fCanvas(canvas)
3201 , fSaveCount(canvas->getSaveCount())
3202{
bsalomon49f085d2014-09-05 13:34:00 -07003203 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003204 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003205 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003206 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003207 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003208 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003209 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003210 canvas->save();
3211 }
mtklein6cfa73a2014-08-13 13:33:49 -07003212
bsalomon49f085d2014-09-05 13:34:00 -07003213 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003214 canvas->concat(*matrix);
3215 }
3216}
3217
3218SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3219 fCanvas->restoreToCount(fSaveCount);
3220}
reede8f30622016-03-23 18:59:25 -07003221
Florin Malitaee424ac2016-12-01 12:47:59 -05003222///////////////////////////////////////////////////////////////////////////////
3223
3224SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3225 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3226
Florin Malita439ace92016-12-02 12:05:41 -05003227SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3228 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3229
Florin Malitaee424ac2016-12-01 12:47:59 -05003230SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3231 (void)this->INHERITED::getSaveLayerStrategy(rec);
3232 return kNoLayer_SaveLayerStrategy;
3233}
3234
3235///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003236
reed73603f32016-09-20 08:42:38 -07003237static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3238static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3239static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3240static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3241static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3242static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003243
3244///////////////////////////////////////////////////////////////////////////////////////////////////
3245
3246SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3247 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3248 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3249 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3250 SkIPoint origin = dev->getOrigin();
3251 SkMatrix ctm = this->getTotalMatrix();
3252 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3253
3254 SkIRect clip = fMCRec->fRasterClip.getBounds();
3255 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003256 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003257 clip.setEmpty();
3258 }
3259
3260 fAllocator->updateHandle(handle, ctm, clip);
3261 return handle;
3262 }
3263 return nullptr;
3264}
3265
3266static bool install(SkBitmap* bm, const SkImageInfo& info,
3267 const SkRasterHandleAllocator::Rec& rec) {
3268 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3269 rec.fReleaseProc, rec.fReleaseCtx);
3270}
3271
3272SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3273 SkBitmap* bm) {
3274 SkRasterHandleAllocator::Rec rec;
3275 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3276 return nullptr;
3277 }
3278 return rec.fHandle;
3279}
3280
3281std::unique_ptr<SkCanvas>
3282SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3283 const SkImageInfo& info, const Rec* rec) {
3284 if (!alloc || !supported_for_raster_canvas(info)) {
3285 return nullptr;
3286 }
3287
3288 SkBitmap bm;
3289 Handle hndl;
3290
3291 if (rec) {
3292 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3293 } else {
3294 hndl = alloc->allocBitmap(info, &bm);
3295 }
3296 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3297}