blob: 844de43b8a33dbd25a1c001291efe550c8a36f19 [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
Matt Sarett31f99ce2017-04-11 08:46:01 -0400750#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
751SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
752 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
753 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
754 , fAllocator(nullptr)
755{
756 inc_canvas();
757
758 SkBitmap tmp(bitmap);
759 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
760 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
761 this->init(device.get(), kDefault_InitFlags);
762}
763#endif
764
reed@android.com8a1c16f2008-12-17 15:59:43 +0000765SkCanvas::~SkCanvas() {
766 // free up the contents of our deque
767 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000768
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769 this->internalRestore(); // restore the last, since we're going away
770
halcanary385fe4d2015-08-26 13:07:48 -0700771 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000772
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 dec_canvas();
774}
775
fmalita53d9f1c2016-01-25 06:23:54 -0800776#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777SkDrawFilter* SkCanvas::getDrawFilter() const {
778 return fMCRec->fFilter;
779}
780
781SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700782 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
784 return filter;
785}
fmalita77650002016-01-21 18:47:11 -0800786#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000788SkMetaData& SkCanvas::getMetaData() {
789 // metadata users are rare, so we lazily allocate it. If that changes we
790 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700791 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000792 fMetaData = new SkMetaData;
793 }
794 return *fMetaData;
795}
796
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797///////////////////////////////////////////////////////////////////////////////
798
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000799void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700800 this->onFlush();
801}
802
803void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000804 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000805 if (device) {
806 device->flush();
807 }
808}
809
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000810SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000811 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000812 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
813}
814
senorblancoafc7cce2016-02-02 18:44:15 -0800815SkIRect SkCanvas::getTopLayerBounds() const {
816 SkBaseDevice* d = this->getTopDevice();
817 if (!d) {
818 return SkIRect::MakeEmpty();
819 }
820 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
821}
822
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000823SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000825 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826 SkASSERT(rec && rec->fLayer);
827 return rec->fLayer->fDevice;
828}
829
Florin Malita0ed3b642017-01-13 16:56:38 +0000830SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000831 return fMCRec->fTopLayer->fDevice;
832}
833
Mike Reed12e946b2017-04-17 10:53:29 -0400834#ifdef SK_SUPPORT_LEGACY_CANVAS_READPIXELS
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000835bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000836 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700837 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700838 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000839 return false;
840 }
841 weAllocated = true;
842 }
843
Mike Reed4edb5d22017-04-17 11:02:51 -0400844 SkPixmap pm;
845 if (bitmap->peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700846 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
847 return true;
848 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000849 }
850
851 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500852 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000853 }
854 return false;
855}
reed@google.com51df9e32010-12-23 19:29:18 +0000856
bsalomon@google.comc6980972011-11-02 19:57:21 +0000857bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000858 SkIRect r = srcRect;
859 const SkISize size = this->getBaseLayerSize();
860 if (!r.intersect(0, 0, size.width(), size.height())) {
861 bitmap->reset();
862 return false;
863 }
864
reed84825042014-09-02 12:50:45 -0700865 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000866 // bitmap will already be reset.
867 return false;
868 }
869 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
870 bitmap->reset();
871 return false;
872 }
873 return true;
874}
Mike Reed12e946b2017-04-17 10:53:29 -0400875#endif
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000876
reed96472de2014-12-10 09:53:42 -0800877bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000878 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000879 if (!device) {
880 return false;
881 }
mtkleinf0f14112014-12-12 08:46:25 -0800882
Matt Sarett03dd6d52017-01-23 12:15:09 -0500883 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000884}
885
Mike Reed12e946b2017-04-17 10:53:29 -0400886bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
887 return pm.addr() && this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y);
888}
889
890bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
891 SkPixmap pm;
892 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
893}
894
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000895bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400896 SkPixmap pm;
897 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700898 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000899 }
900 return false;
901}
902
Matt Sarett03dd6d52017-01-23 12:15:09 -0500903bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000904 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000905 SkBaseDevice* device = this->getDevice();
906 if (!device) {
907 return false;
908 }
909
Matt Sarett03dd6d52017-01-23 12:15:09 -0500910 // This check gives us an early out and prevents generation ID churn on the surface.
911 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
912 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
913 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
914 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000915 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000916
Matt Sarett03dd6d52017-01-23 12:15:09 -0500917 // Tell our owning surface to bump its generation ID.
918 const bool completeOverwrite =
919 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700920 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700921
Matt Sarett03dd6d52017-01-23 12:15:09 -0500922 // This can still fail, most notably in the case of a invalid color type or alpha type
923 // conversion. We could pull those checks into this function and avoid the unnecessary
924 // generation ID bump. But then we would be performing those checks twice, since they
925 // are also necessary at the bitmap/pixmap entry points.
926 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000927}
reed@google.com51df9e32010-12-23 19:29:18 +0000928
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929//////////////////////////////////////////////////////////////////////////////
930
reed2ff1fce2014-12-11 07:07:37 -0800931void SkCanvas::checkForDeferredSave() {
932 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800933 this->doSave();
934 }
935}
936
reedf0090cb2014-11-26 08:55:51 -0800937int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800938#ifdef SK_DEBUG
939 int count = 0;
940 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
941 for (;;) {
942 const MCRec* rec = (const MCRec*)iter.next();
943 if (!rec) {
944 break;
945 }
946 count += 1 + rec->fDeferredSaveCount;
947 }
948 SkASSERT(count == fSaveCount);
949#endif
950 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800951}
952
953int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800954 fSaveCount += 1;
955 fMCRec->fDeferredSaveCount += 1;
956 return this->getSaveCount() - 1; // return our prev value
957}
958
959void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800960 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700961
962 SkASSERT(fMCRec->fDeferredSaveCount > 0);
963 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800964 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800965}
966
967void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800968 if (fMCRec->fDeferredSaveCount > 0) {
969 SkASSERT(fSaveCount > 1);
970 fSaveCount -= 1;
971 fMCRec->fDeferredSaveCount -= 1;
972 } else {
973 // check for underflow
974 if (fMCStack.count() > 1) {
975 this->willRestore();
976 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700977 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800978 this->internalRestore();
979 this->didRestore();
980 }
reedf0090cb2014-11-26 08:55:51 -0800981 }
982}
983
984void SkCanvas::restoreToCount(int count) {
985 // sanity check
986 if (count < 1) {
987 count = 1;
988 }
mtkleinf0f14112014-12-12 08:46:25 -0800989
reedf0090cb2014-11-26 08:55:51 -0800990 int n = this->getSaveCount() - count;
991 for (int i = 0; i < n; ++i) {
992 this->restore();
993 }
994}
995
reed2ff1fce2014-12-11 07:07:37 -0800996void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000997 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700998 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000999 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001000
Mike Reedc42a1cd2017-02-14 14:25:14 -05001001 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001002}
1003
reed4960eee2015-12-18 07:09:18 -08001004bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001005 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001006}
1007
reed4960eee2015-12-18 07:09:18 -08001008bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001009 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001010 SkIRect clipBounds = this->getDeviceClipBounds();
1011 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001012 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001013 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001014
reed96e657d2015-03-10 17:30:07 -07001015 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1016
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001017 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001018 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001019 if (bounds && !imageFilter->canComputeFastBounds()) {
1020 bounds = nullptr;
1021 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001022 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001023 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001024 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001025 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001026
reed96e657d2015-03-10 17:30:07 -07001027 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028 r.roundOut(&ir);
1029 // early exit if the layer's bounds are clipped out
1030 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001031 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -05001032 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -07001033 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001034 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001035 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001036 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037 }
1038 } else { // no user bounds, so just use the clip
1039 ir = clipBounds;
1040 }
reed180aec42015-03-11 10:39:04 -07001041 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001042
reed4960eee2015-12-18 07:09:18 -08001043 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001044 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -07001045 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001046 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001047 }
1048
1049 if (intersection) {
1050 *intersection = ir;
1051 }
1052 return true;
1053}
1054
reed4960eee2015-12-18 07:09:18 -08001055
reed4960eee2015-12-18 07:09:18 -08001056int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1057 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001058}
1059
reed70ee31b2015-12-10 13:44:45 -08001060int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001061 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1062}
1063
1064int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1065 SaveLayerRec rec(origRec);
1066 if (gIgnoreSaveLayerBounds) {
1067 rec.fBounds = nullptr;
1068 }
1069 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1070 fSaveCount += 1;
1071 this->internalSaveLayer(rec, strategy);
1072 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001073}
1074
reeda2217ef2016-07-20 06:04:34 -07001075void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001076 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001077 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001078 SkDraw draw;
1079 SkRasterClip rc;
1080 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1081 if (!dst->accessPixels(&draw.fDst)) {
1082 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001083 }
reeda2217ef2016-07-20 06:04:34 -07001084 draw.fMatrix = &SkMatrix::I();
1085 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001086
1087 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001088 if (filter) {
1089 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1090 }
reeda2217ef2016-07-20 06:04:34 -07001091
Mike Reedc42a1cd2017-02-14 14:25:14 -05001092 int x = src->getOrigin().x() - dstOrigin.x();
1093 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001094 auto special = src->snapSpecial();
1095 if (special) {
Mike Reeda1361362017-03-07 09:37:29 -05001096 dst->drawSpecial(special.get(), x, y, p);
reeda2217ef2016-07-20 06:04:34 -07001097 }
robertphillips7354a4b2015-12-16 05:08:27 -08001098}
reed70ee31b2015-12-10 13:44:45 -08001099
reed129ed1c2016-02-22 06:42:31 -08001100static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1101 const SkPaint* paint) {
1102 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1103 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001104 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001105 const bool hasImageFilter = paint && paint->getImageFilter();
1106
1107 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1108 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1109 // force to L32
1110 return SkImageInfo::MakeN32(w, h, alphaType);
1111 } else {
1112 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001113 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001114 }
1115}
1116
reed4960eee2015-12-18 07:09:18 -08001117void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1118 const SkRect* bounds = rec.fBounds;
1119 const SkPaint* paint = rec.fPaint;
1120 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1121
reed8c30a812016-04-20 16:36:51 -07001122 SkLazyPaint lazyP;
1123 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1124 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001125 SkMatrix remainder;
1126 SkSize scale;
1127 /*
1128 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1129 * but they do handle scaling. To accommodate this, we do the following:
1130 *
1131 * 1. Stash off the current CTM
1132 * 2. Decompose the CTM into SCALE and REMAINDER
1133 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1134 * contains the REMAINDER
1135 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1136 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1137 * of the original imagefilter, and draw that (via drawSprite)
1138 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1139 *
1140 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1141 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1142 */
reed96a04f32016-04-25 09:25:15 -07001143 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001144 stashedMatrix.decomposeScale(&scale, &remainder))
1145 {
1146 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1147 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1148 SkPaint* p = lazyP.set(*paint);
1149 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1150 SkFilterQuality::kLow_SkFilterQuality,
1151 sk_ref_sp(imageFilter)));
1152 imageFilter = p->getImageFilter();
1153 paint = p;
1154 }
reed8c30a812016-04-20 16:36:51 -07001155
junov@chromium.orga907ac32012-02-24 21:54:07 +00001156 // do this before we create the layer. We don't call the public save() since
1157 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001158 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001159
junov@chromium.orga907ac32012-02-24 21:54:07 +00001160 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001161 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001162 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001163 }
1164
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001165 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1166 // the clipRectBounds() call above?
1167 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001168 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001169 }
1170
reed4960eee2015-12-18 07:09:18 -08001171 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001172 SkPixelGeometry geo = fProps.pixelGeometry();
1173 if (paint) {
reed76033be2015-03-14 10:54:31 -07001174 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001175 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001176 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001177 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001178 }
1179 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180
robertphillips5139e502016-07-19 05:10:40 -07001181 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001182 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001183 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001184 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001185 }
reedb2db8982014-11-13 12:41:02 -08001186
robertphillips5139e502016-07-19 05:10:40 -07001187 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001188 paint);
1189
Hal Canary704cd322016-11-07 14:13:52 -05001190 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001191 {
reed70ee31b2015-12-10 13:44:45 -08001192 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001193 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001194 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001195 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001196 preserveLCDText,
1197 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001198 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1199 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001200 return;
reed61f501f2015-04-29 08:34:00 -07001201 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001202 }
Hal Canary704cd322016-11-07 14:13:52 -05001203 DeviceCM* layer =
Mike Reeda1361362017-03-07 09:37:29 -05001204 new DeviceCM(newDevice.get(), paint, this, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001205
Mike Reedb43a3e02017-02-11 10:18:58 -05001206 // only have a "next" if this new layer doesn't affect the clip (rare)
1207 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001208 fMCRec->fLayer = layer;
1209 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001210
Mike Reedc61abee2017-02-28 17:45:27 -05001211 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001212 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001213 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001214 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001215
Mike Reedc42a1cd2017-02-14 14:25:14 -05001216 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1217
1218 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1219 if (layer->fNext) {
1220 // need to punch a hole in the previous device, so we don't draw there, given that
1221 // the new top-layer will allow drawing to happen "below" it.
1222 SkRegion hole(ir);
1223 do {
1224 layer = layer->fNext;
1225 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1226 } while (layer->fNext);
1227 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228}
1229
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001230int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001231 if (0xFF == alpha) {
1232 return this->saveLayer(bounds, nullptr);
1233 } else {
1234 SkPaint tmpPaint;
1235 tmpPaint.setAlpha(alpha);
1236 return this->saveLayer(bounds, &tmpPaint);
1237 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001238}
1239
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240void SkCanvas::internalRestore() {
1241 SkASSERT(fMCStack.count() != 0);
1242
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001243 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244 DeviceCM* layer = fMCRec->fLayer; // may be null
1245 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001246 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247
1248 // now do the normal restore()
1249 fMCRec->~MCRec(); // balanced in save()
1250 fMCStack.pop_back();
1251 fMCRec = (MCRec*)fMCStack.back();
1252
Mike Reedc42a1cd2017-02-14 14:25:14 -05001253 if (fMCRec) {
1254 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1255 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001256
reed@android.com8a1c16f2008-12-17 15:59:43 +00001257 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1258 since if we're being recorded, we don't want to record this (the
1259 recorder will have already recorded the restore).
1260 */
bsalomon49f085d2014-09-05 13:34:00 -07001261 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001262 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001263 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001264 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001265 // restore what we smashed in internalSaveLayer
1266 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001267 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001268 delete layer;
reedb679ca82015-04-07 04:40:48 -07001269 } else {
1270 // we're at the root
reeda499f902015-05-01 09:34:31 -07001271 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001272 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001273 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001275 }
msarettfbfa2582016-08-12 08:29:08 -07001276
1277 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001278 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001279 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1280 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281}
1282
reede8f30622016-03-23 18:59:25 -07001283sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001284 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001285 props = &fProps;
1286 }
1287 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001288}
1289
reede8f30622016-03-23 18:59:25 -07001290sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001291 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001292 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001293}
1294
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001295SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001296 return this->onImageInfo();
1297}
1298
1299SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001300 SkBaseDevice* dev = this->getDevice();
1301 if (dev) {
1302 return dev->imageInfo();
1303 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001304 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001305 }
1306}
1307
brianosman898235c2016-04-06 07:38:23 -07001308bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001309 return this->onGetProps(props);
1310}
1311
1312bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001313 SkBaseDevice* dev = this->getDevice();
1314 if (dev) {
1315 if (props) {
1316 *props = fProps;
1317 }
1318 return true;
1319 } else {
1320 return false;
1321 }
1322}
1323
reed6ceeebd2016-03-09 14:26:26 -08001324bool SkCanvas::peekPixels(SkPixmap* pmap) {
1325 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001326}
1327
reed884e97c2015-05-26 11:31:54 -07001328bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001329 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001330 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001331}
1332
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001333void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001334 SkPixmap pmap;
1335 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001336 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001337 }
1338 if (info) {
1339 *info = pmap.info();
1340 }
1341 if (rowBytes) {
1342 *rowBytes = pmap.rowBytes();
1343 }
1344 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001345 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001346 }
reed884e97c2015-05-26 11:31:54 -07001347 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001348}
1349
reed884e97c2015-05-26 11:31:54 -07001350bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001351 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001352 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001353}
1354
reed@android.com8a1c16f2008-12-17 15:59:43 +00001355/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356
reed7503d602016-07-15 14:23:29 -07001357void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001358 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001359 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001360 paint = &tmp;
1361 }
reed@google.com4b226022011-01-11 18:32:13 +00001362
reed@google.com8926b162012-03-23 15:36:36 +00001363 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001364
reed@android.com8a1c16f2008-12-17 15:59:43 +00001365 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001366 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001367 paint = &looper.paint();
1368 SkImageFilter* filter = paint->getImageFilter();
1369 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001370 if (filter) {
1371 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1372 if (specialImage) {
Mike Reeda1361362017-03-07 09:37:29 -05001373 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint);
Robert Phillips833dcf42016-11-18 08:44:13 -05001374 }
reed@google.com76dd2772012-01-05 21:15:07 +00001375 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001376 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001377 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378 }
reeda2217ef2016-07-20 06:04:34 -07001379
reed@google.com4e2b3d32011-04-07 14:18:59 +00001380 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381}
1382
reed32704672015-12-16 08:27:10 -08001383/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001384
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001385void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001386 if (dx || dy) {
1387 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001388 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001389
reedfe69b502016-09-12 06:31:48 -07001390 // Translate shouldn't affect the is-scale-translateness of the matrix.
1391 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001392
Mike Reedc42a1cd2017-02-14 14:25:14 -05001393 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001394
reedfe69b502016-09-12 06:31:48 -07001395 this->didTranslate(dx,dy);
1396 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001397}
1398
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001399void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001400 SkMatrix m;
1401 m.setScale(sx, sy);
1402 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001403}
1404
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001405void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001406 SkMatrix m;
1407 m.setRotate(degrees);
1408 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409}
1410
bungeman7438bfc2016-07-12 15:01:19 -07001411void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1412 SkMatrix m;
1413 m.setRotate(degrees, px, py);
1414 this->concat(m);
1415}
1416
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001417void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001418 SkMatrix m;
1419 m.setSkew(sx, sy);
1420 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001421}
1422
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001423void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001424 if (matrix.isIdentity()) {
1425 return;
1426 }
1427
reed2ff1fce2014-12-11 07:07:37 -08001428 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001429 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001430 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001431
Mike Reed7627fa52017-02-08 10:07:53 -05001432 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001433
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001434 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001435}
1436
reed8c30a812016-04-20 16:36:51 -07001437void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001438 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001439 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001440
Mike Reedc42a1cd2017-02-14 14:25:14 -05001441 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001442}
1443
1444void SkCanvas::setMatrix(const SkMatrix& matrix) {
1445 this->checkForDeferredSave();
1446 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001447 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448}
1449
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001451 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452}
1453
vjiaoblack95302da2016-07-21 10:25:54 -07001454#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001455void SkCanvas::translateZ(SkScalar z) {
1456 this->checkForDeferredSave();
1457 this->fMCRec->fCurDrawDepth += z;
1458 this->didTranslateZ(z);
1459}
1460
1461SkScalar SkCanvas::getZ() const {
1462 return this->fMCRec->fCurDrawDepth;
1463}
1464
vjiaoblack95302da2016-07-21 10:25:54 -07001465void SkCanvas::setLights(sk_sp<SkLights> lights) {
1466 this->fLights = lights;
1467}
1468
1469sk_sp<SkLights> SkCanvas::getLights() const {
1470 return this->fLights;
1471}
1472#endif
1473
reed@android.com8a1c16f2008-12-17 15:59:43 +00001474//////////////////////////////////////////////////////////////////////////////
1475
Mike Reedc1f77742016-12-09 09:00:50 -05001476void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001477 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001478 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1479 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001480}
1481
Mike Reedc1f77742016-12-09 09:00:50 -05001482void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001483 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001484
Mike Reed7627fa52017-02-08 10:07:53 -05001485 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001486
reedc64eff52015-11-21 12:39:45 -08001487 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001488 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1489 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001490 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001491}
1492
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001493void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1494 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001495 if (fClipRestrictionRect.isEmpty()) {
1496 // we notify the device, but we *dont* resolve deferred saves (since we're just
1497 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001498 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001499 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001500 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001501 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001502 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001503 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001504 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1505 }
1506}
1507
Mike Reedc1f77742016-12-09 09:00:50 -05001508void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001509 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001510 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001511 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001512 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1513 } else {
1514 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001515 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001516}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001517
Mike Reedc1f77742016-12-09 09:00:50 -05001518void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001519 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001520
Brian Salomona3b45d42016-10-03 11:36:16 -04001521 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001522
Mike Reed7627fa52017-02-08 10:07:53 -05001523 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001524
Brian Salomona3b45d42016-10-03 11:36:16 -04001525 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1526 isAA);
1527 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001528}
1529
Mike Reedc1f77742016-12-09 09:00:50 -05001530void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001531 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001532 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001533
1534 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1535 SkRect r;
1536 if (path.isRect(&r)) {
1537 this->onClipRect(r, op, edgeStyle);
1538 return;
1539 }
1540 SkRRect rrect;
1541 if (path.isOval(&r)) {
1542 rrect.setOval(r);
1543 this->onClipRRect(rrect, op, edgeStyle);
1544 return;
1545 }
1546 if (path.isRRect(&rrect)) {
1547 this->onClipRRect(rrect, op, edgeStyle);
1548 return;
1549 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001550 }
robertphillips39f05382015-11-24 09:30:12 -08001551
1552 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001553}
1554
Mike Reedc1f77742016-12-09 09:00:50 -05001555void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001556 AutoValidateClip avc(this);
1557
Brian Salomona3b45d42016-10-03 11:36:16 -04001558 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001559
Mike Reed7627fa52017-02-08 10:07:53 -05001560 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001561
Brian Salomona3b45d42016-10-03 11:36:16 -04001562 const SkPath* rasterClipPath = &path;
1563 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001564 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1565 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001566 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001567}
1568
Mike Reedc1f77742016-12-09 09:00:50 -05001569void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001570 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001571 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001572}
1573
Mike Reedc1f77742016-12-09 09:00:50 -05001574void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001575 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001576
reed@google.com5c3d1472011-02-22 19:12:23 +00001577 AutoValidateClip avc(this);
1578
reed73603f32016-09-20 08:42:38 -07001579 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001580 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001581}
1582
reed@google.com819c9212011-02-23 18:56:55 +00001583#ifdef SK_DEBUG
1584void SkCanvas::validateClip() const {
1585 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001586 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001587 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001588 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001589 return;
1590 }
reed@google.com819c9212011-02-23 18:56:55 +00001591}
1592#endif
1593
Mike Reeda1361362017-03-07 09:37:29 -05001594bool SkCanvas::androidFramework_isClipAA() const {
1595 bool containsAA = false;
1596
1597 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1598
1599 return containsAA;
1600}
1601
1602class RgnAccumulator {
1603 SkRegion* fRgn;
1604public:
1605 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1606 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1607 SkIPoint origin = device->getOrigin();
1608 if (origin.x() | origin.y()) {
1609 rgn->translate(origin.x(), origin.y());
1610 }
1611 fRgn->op(*rgn, SkRegion::kUnion_Op);
1612 }
1613};
1614
1615void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1616 RgnAccumulator accum(rgn);
1617 SkRegion tmp;
1618
1619 rgn->setEmpty();
1620 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001621}
1622
reed@google.com5c3d1472011-02-22 19:12:23 +00001623///////////////////////////////////////////////////////////////////////////////
1624
reed@google.com754de5f2014-02-24 19:38:20 +00001625bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001626 return fMCRec->fRasterClip.isEmpty();
1627
1628 // TODO: should we only use the conservative answer in a recording canvas?
1629#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001630 SkBaseDevice* dev = this->getTopDevice();
1631 // if no device we return true
1632 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001633#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001634}
1635
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001636bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001637 SkBaseDevice* dev = this->getTopDevice();
1638 // if no device we return false
1639 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001640}
1641
msarettfbfa2582016-08-12 08:29:08 -07001642static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1643#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1644 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1645 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1646 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1647 return 0xF != _mm_movemask_ps(mask);
1648#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1649 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1650 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1651 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1652 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1653#else
1654 SkRect devRectAsRect;
1655 SkRect devClipAsRect;
1656 devRect.store(&devRectAsRect.fLeft);
1657 devClip.store(&devClipAsRect.fLeft);
1658 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1659#endif
1660}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001661
msarettfbfa2582016-08-12 08:29:08 -07001662// It's important for this function to not be inlined. Otherwise the compiler will share code
1663// between the fast path and the slow path, resulting in two slow paths.
1664static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1665 const SkMatrix& matrix) {
1666 SkRect deviceRect;
1667 matrix.mapRect(&deviceRect, src);
1668 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1669}
1670
1671bool SkCanvas::quickReject(const SkRect& src) const {
1672#ifdef SK_DEBUG
1673 // Verify that fDeviceClipBounds are set properly.
1674 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001675 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001676 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001677 } else {
msarettfbfa2582016-08-12 08:29:08 -07001678 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001679 }
msarettfbfa2582016-08-12 08:29:08 -07001680
msarett9637ea92016-08-18 14:03:30 -07001681 // Verify that fIsScaleTranslate is set properly.
1682 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001683#endif
1684
msarett9637ea92016-08-18 14:03:30 -07001685 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001686 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1687 }
1688
1689 // We inline the implementation of mapScaleTranslate() for the fast path.
1690 float sx = fMCRec->fMatrix.getScaleX();
1691 float sy = fMCRec->fMatrix.getScaleY();
1692 float tx = fMCRec->fMatrix.getTranslateX();
1693 float ty = fMCRec->fMatrix.getTranslateY();
1694 Sk4f scale(sx, sy, sx, sy);
1695 Sk4f trans(tx, ty, tx, ty);
1696
1697 // Apply matrix.
1698 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1699
1700 // Make sure left < right, top < bottom.
1701 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1702 Sk4f min = Sk4f::Min(ltrb, rblt);
1703 Sk4f max = Sk4f::Max(ltrb, rblt);
1704 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1705 // ARM this sequence generates the fastest (a single instruction).
1706 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1707
1708 // Check if the device rect is NaN or outside the clip.
1709 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001710}
1711
reed@google.com3b3e8952012-08-16 20:53:31 +00001712bool SkCanvas::quickReject(const SkPath& path) const {
1713 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714}
1715
Mike Reed42e8c532017-01-23 14:09:13 -05001716SkRect SkCanvas::onGetLocalClipBounds() const {
1717 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001718 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001719 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001720 }
1721
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001722 SkMatrix inverse;
1723 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001724 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001725 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001726 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001727
Mike Reed42e8c532017-01-23 14:09:13 -05001728 SkRect bounds;
1729 SkRect r;
1730 // adjust it outwards in case we are antialiasing
1731 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001732
Mike Reed42e8c532017-01-23 14:09:13 -05001733 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1734 ibounds.fRight + inset, ibounds.fBottom + inset);
1735 inverse.mapRect(&bounds, r);
1736 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001737}
1738
Mike Reed42e8c532017-01-23 14:09:13 -05001739SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001740 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001741}
1742
reed@android.com8a1c16f2008-12-17 15:59:43 +00001743const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001744 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001745}
1746
Brian Osman11052242016-10-27 14:47:55 -04001747GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001748 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001749 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001750}
1751
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001752GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001753 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001754 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001755}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001756
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001757void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1758 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001759 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001760 if (outer.isEmpty()) {
1761 return;
1762 }
1763 if (inner.isEmpty()) {
1764 this->drawRRect(outer, paint);
1765 return;
1766 }
1767
1768 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001769 // be able to return ...
1770 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001771 //
1772 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001773 if (!outer.getBounds().contains(inner.getBounds())) {
1774 return;
1775 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001776
1777 this->onDrawDRRect(outer, inner, paint);
1778}
1779
reed41af9662015-01-05 07:49:08 -08001780// These need to stop being virtual -- clients need to override the onDraw... versions
1781
1782void SkCanvas::drawPaint(const SkPaint& paint) {
1783 this->onDrawPaint(paint);
1784}
1785
1786void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1787 this->onDrawRect(r, paint);
1788}
1789
msarettdca352e2016-08-26 06:37:45 -07001790void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1791 if (region.isEmpty()) {
1792 return;
1793 }
1794
1795 if (region.isRect()) {
1796 return this->drawIRect(region.getBounds(), paint);
1797 }
1798
1799 this->onDrawRegion(region, paint);
1800}
1801
reed41af9662015-01-05 07:49:08 -08001802void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1803 this->onDrawOval(r, paint);
1804}
1805
1806void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1807 this->onDrawRRect(rrect, paint);
1808}
1809
1810void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1811 this->onDrawPoints(mode, count, pts, paint);
1812}
1813
Mike Reede88a1cb2017-03-17 09:50:46 -04001814void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1815 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001816 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001817 this->onDrawVerticesObject(vertices.get(), mode, paint);
1818}
1819
1820void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1821 RETURN_ON_NULL(vertices);
1822 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001823}
1824
1825void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1826 this->onDrawPath(path, paint);
1827}
1828
reeda85d4d02015-05-06 12:56:48 -07001829void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001830 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001831 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001832}
1833
reede47829b2015-08-06 10:02:53 -07001834void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1835 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001836 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001837 if (dst.isEmpty() || src.isEmpty()) {
1838 return;
1839 }
1840 this->onDrawImageRect(image, &src, dst, paint, constraint);
1841}
reed41af9662015-01-05 07:49:08 -08001842
reed84984ef2015-07-17 07:09:43 -07001843void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1844 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001845 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001846 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001847}
1848
reede47829b2015-08-06 10:02:53 -07001849void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1850 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001851 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001852 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1853 constraint);
1854}
reede47829b2015-08-06 10:02:53 -07001855
reed4c21dc52015-06-25 12:32:03 -07001856void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1857 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001858 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001859 if (dst.isEmpty()) {
1860 return;
1861 }
msarett552bca92016-08-03 06:53:26 -07001862 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1863 this->onDrawImageNine(image, center, dst, paint);
1864 } else {
reede47829b2015-08-06 10:02:53 -07001865 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001866 }
reed4c21dc52015-06-25 12:32:03 -07001867}
1868
msarett16882062016-08-16 09:31:08 -07001869void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1870 const SkPaint* paint) {
1871 RETURN_ON_NULL(image);
1872 if (dst.isEmpty()) {
1873 return;
1874 }
msarett71df2d72016-09-30 12:41:42 -07001875
1876 SkIRect bounds;
1877 Lattice latticePlusBounds = lattice;
1878 if (!latticePlusBounds.fBounds) {
1879 bounds = SkIRect::MakeWH(image->width(), image->height());
1880 latticePlusBounds.fBounds = &bounds;
1881 }
1882
1883 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1884 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001885 } else {
1886 this->drawImageRect(image, dst, paint);
1887 }
1888}
1889
reed41af9662015-01-05 07:49:08 -08001890void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001891 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001892 return;
1893 }
reed41af9662015-01-05 07:49:08 -08001894 this->onDrawBitmap(bitmap, dx, dy, paint);
1895}
1896
reede47829b2015-08-06 10:02:53 -07001897void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001898 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001899 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001900 return;
1901 }
reede47829b2015-08-06 10:02:53 -07001902 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001903}
1904
reed84984ef2015-07-17 07:09:43 -07001905void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1906 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001907 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001908}
1909
reede47829b2015-08-06 10:02:53 -07001910void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1911 SrcRectConstraint constraint) {
1912 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1913 constraint);
1914}
reede47829b2015-08-06 10:02:53 -07001915
reed41af9662015-01-05 07:49:08 -08001916void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1917 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001918 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001919 return;
1920 }
msarett552bca92016-08-03 06:53:26 -07001921 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1922 this->onDrawBitmapNine(bitmap, center, dst, paint);
1923 } else {
reeda5517e22015-07-14 10:54:12 -07001924 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001925 }
reed41af9662015-01-05 07:49:08 -08001926}
1927
msarettc573a402016-08-02 08:05:56 -07001928void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1929 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001930 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001931 return;
1932 }
msarett71df2d72016-09-30 12:41:42 -07001933
1934 SkIRect bounds;
1935 Lattice latticePlusBounds = lattice;
1936 if (!latticePlusBounds.fBounds) {
1937 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1938 latticePlusBounds.fBounds = &bounds;
1939 }
1940
1941 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1942 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001943 } else {
msarett16882062016-08-16 09:31:08 -07001944 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001945 }
msarettc573a402016-08-02 08:05:56 -07001946}
1947
reed71c3c762015-06-24 10:29:17 -07001948void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001949 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001950 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001951 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001952 if (count <= 0) {
1953 return;
1954 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001955 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001956 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001957 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001958}
1959
reedf70b5312016-03-04 16:36:20 -08001960void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1961 if (key) {
1962 this->onDrawAnnotation(rect, key, value);
1963 }
1964}
1965
reede47829b2015-08-06 10:02:53 -07001966void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1967 const SkPaint* paint, SrcRectConstraint constraint) {
1968 if (src) {
1969 this->drawImageRect(image, *src, dst, paint, constraint);
1970 } else {
1971 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1972 dst, paint, constraint);
1973 }
1974}
1975void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1976 const SkPaint* paint, SrcRectConstraint constraint) {
1977 if (src) {
1978 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1979 } else {
1980 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1981 dst, paint, constraint);
1982 }
1983}
1984
tomhudsoncb3bd182016-05-18 07:24:16 -07001985void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1986 SkIRect layer_bounds = this->getTopLayerBounds();
1987 if (matrix) {
1988 *matrix = this->getTotalMatrix();
1989 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1990 }
1991 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001992 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001993 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1994 }
1995}
1996
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997//////////////////////////////////////////////////////////////////////////////
1998// These are the virtual drawing methods
1999//////////////////////////////////////////////////////////////////////////////
2000
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002001void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002002 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002003 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2004 }
2005}
2006
reed41af9662015-01-05 07:49:08 -08002007void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002008 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002009 this->internalDrawPaint(paint);
2010}
2011
2012void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002013 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002014
2015 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002016 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002017 }
2018
reed@google.com4e2b3d32011-04-07 14:18:59 +00002019 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002020}
2021
reed41af9662015-01-05 07:49:08 -08002022void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2023 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002024 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002025 if ((long)count <= 0) {
2026 return;
2027 }
2028
Mike Reed822128b2017-02-28 16:41:03 -05002029 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002030 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002031 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002032 // special-case 2 points (common for drawing a single line)
2033 if (2 == count) {
2034 r.set(pts[0], pts[1]);
2035 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002036 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002037 }
Mike Reed822128b2017-02-28 16:41:03 -05002038 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002039 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2040 return;
2041 }
2042 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002043 }
reed@google.coma584aed2012-05-16 14:06:02 +00002044
halcanary96fcdcc2015-08-27 07:41:13 -07002045 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002046
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002047 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002048
reed@android.com8a1c16f2008-12-17 15:59:43 +00002049 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002050 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002051 }
reed@google.com4b226022011-01-11 18:32:13 +00002052
reed@google.com4e2b3d32011-04-07 14:18:59 +00002053 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002054}
2055
reed4a167172016-08-18 17:15:25 -07002056static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2057 return ((intptr_t)paint.getImageFilter() |
2058#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2059 (intptr_t)canvas->getDrawFilter() |
2060#endif
2061 (intptr_t)paint.getLooper() ) != 0;
2062}
2063
reed41af9662015-01-05 07:49:08 -08002064void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002065 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002066 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002067 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2068 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2069 SkRect tmp(r);
2070 tmp.sort();
2071
Mike Reed822128b2017-02-28 16:41:03 -05002072 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002073 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2074 return;
2075 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002076 }
reed@google.com4b226022011-01-11 18:32:13 +00002077
reed4a167172016-08-18 17:15:25 -07002078 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002079 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002080
reed4a167172016-08-18 17:15:25 -07002081 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002082 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002083 }
2084
2085 LOOPER_END
2086 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002087 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002088 SkDrawIter iter(this);
2089 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002090 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002091 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002092 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093}
2094
msarett44df6512016-08-25 13:54:30 -07002095void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002096 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002097 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002098 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002099 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2100 return;
2101 }
msarett44df6512016-08-25 13:54:30 -07002102 }
2103
Mike Reed822128b2017-02-28 16:41:03 -05002104 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002105
2106 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002107 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002108 }
2109
2110 LOOPER_END
2111}
2112
reed41af9662015-01-05 07:49:08 -08002113void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002114 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002115 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002116 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002117 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2118 return;
2119 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002120 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002121
Mike Reed822128b2017-02-28 16:41:03 -05002122 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002123
2124 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002125 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002126 }
2127
2128 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002129}
2130
bsalomonac3aa242016-08-19 11:25:19 -07002131void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2132 SkScalar sweepAngle, bool useCenter,
2133 const SkPaint& paint) {
2134 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002135 if (paint.canComputeFastBounds()) {
2136 SkRect storage;
2137 // Note we're using the entire oval as the bounds.
2138 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2139 return;
2140 }
bsalomonac3aa242016-08-19 11:25:19 -07002141 }
2142
Mike Reed822128b2017-02-28 16:41:03 -05002143 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002144
2145 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002146 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002147 }
2148
2149 LOOPER_END
2150}
2151
reed41af9662015-01-05 07:49:08 -08002152void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002153 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002154 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002155 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002156 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2157 return;
2158 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002159 }
2160
2161 if (rrect.isRect()) {
2162 // call the non-virtual version
2163 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002164 return;
2165 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002166 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002167 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2168 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002169 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002170
Mike Reed822128b2017-02-28 16:41:03 -05002171 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002172
2173 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002174 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002175 }
2176
2177 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002178}
2179
Mike Reed822128b2017-02-28 16:41:03 -05002180void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002181 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002182 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002183 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2184 return;
2185 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002186 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002187
Mike Reed822128b2017-02-28 16:41:03 -05002188 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002189
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002190 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002191 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002192 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002193
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002194 LOOPER_END
2195}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002196
reed41af9662015-01-05 07:49:08 -08002197void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002198 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002199 if (!path.isFinite()) {
2200 return;
2201 }
2202
Mike Reed822128b2017-02-28 16:41:03 -05002203 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002204 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002205 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002206 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2207 return;
2208 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002209 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002210
Mike Reed822128b2017-02-28 16:41:03 -05002211 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002212 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002213 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002214 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002215 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002216 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002217
Mike Reed822128b2017-02-28 16:41:03 -05002218 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002219
2220 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002221 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002222 }
2223
reed@google.com4e2b3d32011-04-07 14:18:59 +00002224 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002225}
2226
reed262a71b2015-12-05 13:07:27 -08002227bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002228 if (!paint.getImageFilter()) {
2229 return false;
2230 }
2231
2232 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002233 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002234 return false;
2235 }
2236
2237 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2238 // Once we can filter and the filter will return a result larger than itself, we should be
2239 // able to remove this constraint.
2240 // skbug.com/4526
2241 //
2242 SkPoint pt;
2243 ctm.mapXY(x, y, &pt);
2244 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2245 return ir.contains(fMCRec->fRasterClip.getBounds());
2246}
2247
reeda85d4d02015-05-06 12:56:48 -07002248void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002249 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002250 SkRect bounds = SkRect::MakeXYWH(x, y,
2251 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002252 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002253 SkRect tmp = bounds;
2254 if (paint) {
2255 paint->computeFastBounds(tmp, &tmp);
2256 }
2257 if (this->quickReject(tmp)) {
2258 return;
2259 }
reeda85d4d02015-05-06 12:56:48 -07002260 }
halcanary9d524f22016-03-29 09:03:52 -07002261
reeda85d4d02015-05-06 12:56:48 -07002262 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002263 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002264 paint = lazy.init();
2265 }
reed262a71b2015-12-05 13:07:27 -08002266
reeda2217ef2016-07-20 06:04:34 -07002267 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002268 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2269 *paint);
2270 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002271 special = this->getDevice()->makeSpecial(image);
2272 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002273 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002274 }
2275 }
2276
reed262a71b2015-12-05 13:07:27 -08002277 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2278
reeda85d4d02015-05-06 12:56:48 -07002279 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002280 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002281 if (special) {
2282 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002283 iter.fDevice->ctm().mapXY(x, y, &pt);
2284 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002285 SkScalarRoundToInt(pt.fX),
2286 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002287 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002288 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002289 }
reeda85d4d02015-05-06 12:56:48 -07002290 }
halcanary9d524f22016-03-29 09:03:52 -07002291
reeda85d4d02015-05-06 12:56:48 -07002292 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002293}
2294
reed41af9662015-01-05 07:49:08 -08002295void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002296 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002297 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002298 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002299 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002300 if (paint) {
2301 paint->computeFastBounds(dst, &storage);
2302 }
2303 if (this->quickReject(storage)) {
2304 return;
2305 }
reeda85d4d02015-05-06 12:56:48 -07002306 }
2307 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002308 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002309 paint = lazy.init();
2310 }
halcanary9d524f22016-03-29 09:03:52 -07002311
senorblancoc41e7e12015-12-07 12:51:30 -08002312 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002313 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002314
reeda85d4d02015-05-06 12:56:48 -07002315 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002316 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002317 }
halcanary9d524f22016-03-29 09:03:52 -07002318
reeda85d4d02015-05-06 12:56:48 -07002319 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002320}
2321
reed41af9662015-01-05 07:49:08 -08002322void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002323 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 SkDEBUGCODE(bitmap.validate();)
2325
reed33366972015-10-08 09:22:02 -07002326 if (bitmap.drawsNothing()) {
2327 return;
2328 }
2329
2330 SkLazyPaint lazy;
2331 if (nullptr == paint) {
2332 paint = lazy.init();
2333 }
2334
Mike Reed822128b2017-02-28 16:41:03 -05002335 SkRect bounds;
2336 bitmap.getBounds(&bounds);
2337 bounds.offset(x, y);
2338 bool canFastBounds = paint->canComputeFastBounds();
2339 if (canFastBounds) {
2340 SkRect storage;
2341 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002342 return;
2343 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002344 }
reed@google.com4b226022011-01-11 18:32:13 +00002345
reeda2217ef2016-07-20 06:04:34 -07002346 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002347 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2348 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002349 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002350 special = this->getDevice()->makeSpecial(bitmap);
2351 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002352 drawAsSprite = false;
2353 }
2354 }
2355
Mike Reed822128b2017-02-28 16:41:03 -05002356 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2357
2358 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002359
2360 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002361 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002362 if (special) {
reed262a71b2015-12-05 13:07:27 -08002363 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002364 iter.fDevice->ctm().mapXY(x, y, &pt);
2365 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002366 SkScalarRoundToInt(pt.fX),
2367 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002368 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002369 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002370 }
reed33366972015-10-08 09:22:02 -07002371 }
msarettfbfa2582016-08-12 08:29:08 -07002372
reed33366972015-10-08 09:22:02 -07002373 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002374}
2375
reed@google.com9987ec32011-09-07 11:57:52 +00002376// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002377void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002378 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002379 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002380 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002381 return;
2382 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002383
halcanary96fcdcc2015-08-27 07:41:13 -07002384 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002385 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002386 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2387 return;
2388 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002389 }
reed@google.com3d608122011-11-21 15:16:16 +00002390
reed@google.com33535f32012-09-25 15:37:50 +00002391 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002392 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002393 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002394 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002395
senorblancoc41e7e12015-12-07 12:51:30 -08002396 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002397 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002398
reed@google.com33535f32012-09-25 15:37:50 +00002399 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002400 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002401 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002402
reed@google.com33535f32012-09-25 15:37:50 +00002403 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002404}
2405
reed41af9662015-01-05 07:49:08 -08002406void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002407 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002408 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002409 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002410 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002411}
2412
reed4c21dc52015-06-25 12:32:03 -07002413void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2414 const SkPaint* paint) {
2415 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002416
halcanary96fcdcc2015-08-27 07:41:13 -07002417 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002418 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002419 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2420 return;
2421 }
reed@google.com3d608122011-11-21 15:16:16 +00002422 }
halcanary9d524f22016-03-29 09:03:52 -07002423
reed4c21dc52015-06-25 12:32:03 -07002424 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002425 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002426 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002427 }
halcanary9d524f22016-03-29 09:03:52 -07002428
senorblancoc41e7e12015-12-07 12:51:30 -08002429 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002430
reed4c21dc52015-06-25 12:32:03 -07002431 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002432 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002433 }
halcanary9d524f22016-03-29 09:03:52 -07002434
reed4c21dc52015-06-25 12:32:03 -07002435 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002436}
2437
reed41af9662015-01-05 07:49:08 -08002438void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2439 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002440 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002441 SkDEBUGCODE(bitmap.validate();)
2442
halcanary96fcdcc2015-08-27 07:41:13 -07002443 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002444 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002445 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2446 return;
2447 }
reed4c21dc52015-06-25 12:32:03 -07002448 }
halcanary9d524f22016-03-29 09:03:52 -07002449
reed4c21dc52015-06-25 12:32:03 -07002450 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002451 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002452 paint = lazy.init();
2453 }
halcanary9d524f22016-03-29 09:03:52 -07002454
senorblancoc41e7e12015-12-07 12:51:30 -08002455 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002456
reed4c21dc52015-06-25 12:32:03 -07002457 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002458 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002459 }
halcanary9d524f22016-03-29 09:03:52 -07002460
reed4c21dc52015-06-25 12:32:03 -07002461 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002462}
2463
msarett16882062016-08-16 09:31:08 -07002464void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2465 const SkPaint* paint) {
2466 if (nullptr == paint || paint->canComputeFastBounds()) {
2467 SkRect storage;
2468 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2469 return;
2470 }
2471 }
2472
2473 SkLazyPaint lazy;
2474 if (nullptr == paint) {
2475 paint = lazy.init();
2476 }
2477
2478 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2479
2480 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002481 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002482 }
2483
2484 LOOPER_END
2485}
2486
2487void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2488 const SkRect& dst, const SkPaint* paint) {
2489 if (nullptr == paint || paint->canComputeFastBounds()) {
2490 SkRect storage;
2491 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2492 return;
2493 }
2494 }
2495
2496 SkLazyPaint lazy;
2497 if (nullptr == paint) {
2498 paint = lazy.init();
2499 }
2500
2501 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2502
2503 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002504 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002505 }
2506
2507 LOOPER_END
2508}
2509
reed@google.comf67e4cf2011-03-15 20:56:58 +00002510class SkDeviceFilteredPaint {
2511public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002512 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002513 uint32_t filteredFlags = device->filterTextFlags(paint);
2514 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002515 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002516 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002517 fPaint = newPaint;
2518 } else {
2519 fPaint = &paint;
2520 }
2521 }
2522
reed@google.comf67e4cf2011-03-15 20:56:58 +00002523 const SkPaint& paint() const { return *fPaint; }
2524
2525private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002526 const SkPaint* fPaint;
2527 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002528};
2529
reed@google.come0d9ce82014-04-23 04:00:17 +00002530void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2531 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002532 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002533
2534 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002535 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002536 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002537 }
2538
reed@google.com4e2b3d32011-04-07 14:18:59 +00002539 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002540}
2541
reed@google.come0d9ce82014-04-23 04:00:17 +00002542void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2543 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002544 SkPoint textOffset = SkPoint::Make(0, 0);
2545
halcanary96fcdcc2015-08-27 07:41:13 -07002546 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002547
reed@android.com8a1c16f2008-12-17 15:59:43 +00002548 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002549 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002550 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002551 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002552 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002553
reed@google.com4e2b3d32011-04-07 14:18:59 +00002554 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002555}
2556
reed@google.come0d9ce82014-04-23 04:00:17 +00002557void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2558 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002559
2560 SkPoint textOffset = SkPoint::Make(0, constY);
2561
halcanary96fcdcc2015-08-27 07:41:13 -07002562 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002563
reed@android.com8a1c16f2008-12-17 15:59:43 +00002564 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002565 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002566 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002567 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002568 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002569
reed@google.com4e2b3d32011-04-07 14:18:59 +00002570 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002571}
2572
reed@google.come0d9ce82014-04-23 04:00:17 +00002573void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2574 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002575 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002576
reed@android.com8a1c16f2008-12-17 15:59:43 +00002577 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002578 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002579 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002580 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002581
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002582 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002583}
2584
reed45561a02016-07-07 12:47:17 -07002585void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2586 const SkRect* cullRect, const SkPaint& paint) {
2587 if (cullRect && this->quickReject(*cullRect)) {
2588 return;
2589 }
2590
2591 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2592
2593 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002594 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002595 }
2596
2597 LOOPER_END
2598}
2599
fmalita00d5c2c2014-08-21 08:53:26 -07002600void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2601 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002602
fmalita85d5eb92015-03-04 11:20:12 -08002603 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002604 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002605 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002606 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002607 SkRect tmp;
2608 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2609 return;
2610 }
2611 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002612 }
2613
fmalita024f9962015-03-03 19:08:17 -08002614 // We cannot filter in the looper as we normally do, because the paint is
2615 // incomplete at this point (text-related attributes are embedded within blob run paints).
2616 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002617 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002618
fmalita85d5eb92015-03-04 11:20:12 -08002619 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002620
fmalitaaa1b9122014-08-28 14:32:24 -07002621 while (iter.next()) {
2622 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002623 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002624 }
2625
fmalitaaa1b9122014-08-28 14:32:24 -07002626 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002627
2628 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002629}
2630
reed@google.come0d9ce82014-04-23 04:00:17 +00002631// These will become non-virtual, so they always call the (virtual) onDraw... method
2632void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2633 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002634 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002635 if (byteLength) {
2636 this->onDrawText(text, byteLength, x, y, paint);
2637 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002638}
2639void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2640 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002641 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002642 if (byteLength) {
2643 this->onDrawPosText(text, byteLength, pos, paint);
2644 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002645}
2646void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2647 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002648 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002649 if (byteLength) {
2650 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2651 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002652}
2653void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2654 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002655 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002656 if (byteLength) {
2657 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2658 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002659}
reed45561a02016-07-07 12:47:17 -07002660void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2661 const SkRect* cullRect, const SkPaint& paint) {
2662 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2663 if (byteLength) {
2664 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2665 }
2666}
fmalita00d5c2c2014-08-21 08:53:26 -07002667void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2668 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002669 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002670 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002671 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002672}
reed@google.come0d9ce82014-04-23 04:00:17 +00002673
Mike Reede88a1cb2017-03-17 09:50:46 -04002674void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2675 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002676 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2677 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2678
2679 while (iter.next()) {
2680 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002681 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002682 }
2683
2684 LOOPER_END
2685}
2686
dandovb3c9d1c2014-08-12 08:34:29 -07002687void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002688 const SkPoint texCoords[4], SkBlendMode bmode,
2689 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002690 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002691 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002692 return;
2693 }
mtklein6cfa73a2014-08-13 13:33:49 -07002694
Mike Reedfaba3712016-11-03 14:45:31 -04002695 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002696}
2697
2698void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002699 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002700 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002701 // Since a patch is always within the convex hull of the control points, we discard it when its
2702 // bounding rectangle is completely outside the current clip.
2703 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002704 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002705 if (this->quickReject(bounds)) {
2706 return;
2707 }
mtklein6cfa73a2014-08-13 13:33:49 -07002708
halcanary96fcdcc2015-08-27 07:41:13 -07002709 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002710
dandovecfff212014-08-04 10:02:00 -07002711 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002712 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002713 }
mtklein6cfa73a2014-08-13 13:33:49 -07002714
dandovecfff212014-08-04 10:02:00 -07002715 LOOPER_END
2716}
2717
reeda8db7282015-07-07 10:22:31 -07002718void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002719 RETURN_ON_NULL(dr);
2720 if (x || y) {
2721 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2722 this->onDrawDrawable(dr, &matrix);
2723 } else {
2724 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002725 }
2726}
2727
reeda8db7282015-07-07 10:22:31 -07002728void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002729 RETURN_ON_NULL(dr);
2730 if (matrix && matrix->isIdentity()) {
2731 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002732 }
reede3b38ce2016-01-08 09:18:44 -08002733 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002734}
2735
2736void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002737 // drawable bounds are no longer reliable (e.g. android displaylist)
2738 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002739 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002740}
2741
reed71c3c762015-06-24 10:29:17 -07002742void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002743 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002744 const SkRect* cull, const SkPaint* paint) {
2745 if (cull && this->quickReject(*cull)) {
2746 return;
2747 }
2748
2749 SkPaint pnt;
2750 if (paint) {
2751 pnt = *paint;
2752 }
halcanary9d524f22016-03-29 09:03:52 -07002753
halcanary96fcdcc2015-08-27 07:41:13 -07002754 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002755 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002756 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002757 }
2758 LOOPER_END
2759}
2760
reedf70b5312016-03-04 16:36:20 -08002761void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2762 SkASSERT(key);
2763
2764 SkPaint paint;
2765 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2766 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002767 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002768 }
2769 LOOPER_END
2770}
2771
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772//////////////////////////////////////////////////////////////////////////////
2773// These methods are NOT virtual, and therefore must call back into virtual
2774// methods, rather than actually drawing themselves.
2775//////////////////////////////////////////////////////////////////////////////
2776
reed374772b2016-10-05 17:33:02 -07002777void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002778 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779 SkPaint paint;
2780
2781 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002782 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783 this->drawPaint(paint);
2784}
2785
2786void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002787 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002788 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002789 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2790}
2791
Mike Reed3661bc92017-02-22 13:21:42 -05002792void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002795
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796 pts[0].set(x0, y0);
2797 pts[1].set(x1, y1);
2798 this->drawPoints(kLines_PointMode, 2, pts, paint);
2799}
2800
Mike Reed3661bc92017-02-22 13:21:42 -05002801void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002802 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002803 if (radius < 0) {
2804 radius = 0;
2805 }
2806
2807 SkRect r;
2808 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002809 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002810}
2811
2812void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2813 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002814 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002815 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002816 SkRRect rrect;
2817 rrect.setRectXY(r, rx, ry);
2818 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002819 } else {
2820 this->drawRect(r, paint);
2821 }
2822}
2823
reed@android.com8a1c16f2008-12-17 15:59:43 +00002824void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2825 SkScalar sweepAngle, bool useCenter,
2826 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002827 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002828 if (oval.isEmpty() || !sweepAngle) {
2829 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830 }
bsalomon21af9ca2016-08-25 12:29:23 -07002831 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002832}
2833
2834void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2835 const SkPath& path, SkScalar hOffset,
2836 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002837 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002838 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002839
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840 matrix.setTranslate(hOffset, vOffset);
2841 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2842}
2843
reed@android.comf76bacf2009-05-13 14:00:33 +00002844///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002845
2846/**
2847 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2848 * against the playback cost of recursing into the subpicture to get at its actual ops.
2849 *
2850 * For now we pick a conservatively small value, though measurement (and other heuristics like
2851 * the type of ops contained) may justify changing this value.
2852 */
2853#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002854
reedd5fa1a42014-08-09 11:08:05 -07002855void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002856 RETURN_ON_NULL(picture);
2857
reed1c2c4412015-04-30 13:09:24 -07002858 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002859 if (matrix && matrix->isIdentity()) {
2860 matrix = nullptr;
2861 }
2862 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2863 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2864 picture->playback(this);
2865 } else {
2866 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002867 }
2868}
robertphillips9b14f262014-06-04 05:40:44 -07002869
reedd5fa1a42014-08-09 11:08:05 -07002870void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2871 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002872 if (!paint || paint->canComputeFastBounds()) {
2873 SkRect bounds = picture->cullRect();
2874 if (paint) {
2875 paint->computeFastBounds(bounds, &bounds);
2876 }
2877 if (matrix) {
2878 matrix->mapRect(&bounds);
2879 }
2880 if (this->quickReject(bounds)) {
2881 return;
2882 }
2883 }
2884
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002885 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002886 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002887}
2888
vjiaoblack95302da2016-07-21 10:25:54 -07002889#ifdef SK_EXPERIMENTAL_SHADOWING
2890void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2891 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002892 const SkPaint* paint,
2893 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002894 RETURN_ON_NULL(picture);
2895
2896 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2897
vjiaoblacke6f5d562016-08-25 06:30:23 -07002898 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002899}
2900
2901void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2902 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002903 const SkPaint* paint,
2904 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002905 if (!paint || paint->canComputeFastBounds()) {
2906 SkRect bounds = picture->cullRect();
2907 if (paint) {
2908 paint->computeFastBounds(bounds, &bounds);
2909 }
2910 if (matrix) {
2911 matrix->mapRect(&bounds);
2912 }
2913 if (this->quickReject(bounds)) {
2914 return;
2915 }
2916 }
2917
2918 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2919
vjiaoblacke6f5d562016-08-25 06:30:23 -07002920 sk_sp<SkImage> povDepthMap;
2921 sk_sp<SkImage> diffuseMap;
2922
vjiaoblack904527d2016-08-09 09:32:09 -07002923 // povDepthMap
2924 {
2925 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002926 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2927 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002928 sk_sp<SkLights> povLight = builder.finish();
2929
2930 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2931 picture->cullRect().height(),
2932 kBGRA_8888_SkColorType,
2933 kOpaque_SkAlphaType);
2934
2935 // Create a new surface (that matches the backend of canvas)
2936 // to create the povDepthMap
2937 sk_sp<SkSurface> surf(this->makeSurface(info));
2938
2939 // Wrap another SPFCanvas around the surface
2940 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2941 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2942
2943 // set the depth map canvas to have the light as the user's POV
2944 depthMapCanvas->setLights(std::move(povLight));
2945
2946 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002947 povDepthMap = surf->makeImageSnapshot();
2948 }
2949
2950 // diffuseMap
2951 {
2952 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2953 picture->cullRect().height(),
2954 kBGRA_8888_SkColorType,
2955 kOpaque_SkAlphaType);
2956
2957 sk_sp<SkSurface> surf(this->makeSurface(info));
2958 surf->getCanvas()->drawPicture(picture);
2959
2960 diffuseMap = surf->makeImageSnapshot();
2961 }
vjiaoblack904527d2016-08-09 09:32:09 -07002962
2963 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
2964 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07002965 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
2966 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07002967
2968 // TODO: pass the depth to the shader in vertices, or uniforms
2969 // so we don't have to render depth and color separately
2970 for (int i = 0; i < fLights->numLights(); ++i) {
2971 // skip over ambient lights; they don't cast shadows
2972 // lights that have shadow maps do not need updating (because lights are immutable)
2973 sk_sp<SkImage> depthMap;
2974 SkISize shMapSize;
2975
2976 if (fLights->light(i).getShadowMap() != nullptr) {
2977 continue;
2978 }
2979
2980 if (fLights->light(i).isRadial()) {
2981 shMapSize.fHeight = 1;
2982 shMapSize.fWidth = (int) picture->cullRect().width();
2983
2984 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
2985 kBGRA_8888_SkColorType,
2986 kOpaque_SkAlphaType);
2987
2988 // Create new surface (that matches the backend of canvas)
2989 // for each shadow map
2990 sk_sp<SkSurface> surf(this->makeSurface(info));
2991
2992 // Wrap another SPFCanvas around the surface
2993 SkCanvas* depthMapCanvas = surf->getCanvas();
2994
2995 SkLights::Builder builder;
2996 builder.add(fLights->light(i));
2997 sk_sp<SkLights> curLight = builder.finish();
2998
2999 sk_sp<SkShader> shadowMapShader;
3000 shadowMapShader = SkRadialShadowMapShader::Make(
3001 povDepthShader, curLight,
3002 (int) picture->cullRect().width(),
3003 (int) picture->cullRect().height());
3004
3005 SkPaint shadowMapPaint;
3006 shadowMapPaint.setShader(std::move(shadowMapShader));
3007
3008 depthMapCanvas->setLights(curLight);
3009
3010 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3011 diffuseMap->height()),
3012 shadowMapPaint);
3013
3014 depthMap = surf->makeImageSnapshot();
3015
3016 } else {
3017 // TODO: compute the correct size of the depth map from the light properties
3018 // TODO: maybe add a kDepth_8_SkColorType
3019 // TODO: find actual max depth of picture
3020 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3021 fLights->light(i), 255,
3022 (int) picture->cullRect().width(),
3023 (int) picture->cullRect().height());
3024
3025 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3026 kBGRA_8888_SkColorType,
3027 kOpaque_SkAlphaType);
3028
3029 // Create a new surface (that matches the backend of canvas)
3030 // for each shadow map
3031 sk_sp<SkSurface> surf(this->makeSurface(info));
3032
3033 // Wrap another SPFCanvas around the surface
3034 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3035 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3036 depthMapCanvas->setShadowParams(params);
3037
3038 // set the depth map canvas to have the light we're drawing.
3039 SkLights::Builder builder;
3040 builder.add(fLights->light(i));
3041 sk_sp<SkLights> curLight = builder.finish();
3042 depthMapCanvas->setLights(std::move(curLight));
3043
3044 depthMapCanvas->drawPicture(picture);
3045 depthMap = surf->makeImageSnapshot();
3046 }
3047
3048 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3049 fLights->light(i).setShadowMap(std::move(depthMap));
3050 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3051 // we blur the variance map
3052 SkPaint blurPaint;
3053 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3054 params.fShadowRadius, nullptr));
3055
3056 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3057 kBGRA_8888_SkColorType,
3058 kOpaque_SkAlphaType);
3059
3060 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3061
3062 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3063
3064 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3065 }
3066 }
3067
3068 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003069 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3070 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003071 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003072 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003073 diffuseMap->height(),
3074 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003075
3076 shadowPaint.setShader(shadowShader);
3077
3078 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003079}
3080#endif
3081
reed@android.com8a1c16f2008-12-17 15:59:43 +00003082///////////////////////////////////////////////////////////////////////////////
3083///////////////////////////////////////////////////////////////////////////////
3084
reed3aafe112016-08-18 12:45:34 -07003085SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003086 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003087
3088 SkASSERT(canvas);
3089
reed3aafe112016-08-18 12:45:34 -07003090 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003091 fDone = !fImpl->next();
3092}
3093
3094SkCanvas::LayerIter::~LayerIter() {
3095 fImpl->~SkDrawIter();
3096}
3097
3098void SkCanvas::LayerIter::next() {
3099 fDone = !fImpl->next();
3100}
3101
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003102SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003103 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003104}
3105
3106const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003107 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003108}
3109
3110const SkPaint& SkCanvas::LayerIter::paint() const {
3111 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003112 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003113 paint = &fDefaultPaint;
3114 }
3115 return *paint;
3116}
3117
Mike Reeda1361362017-03-07 09:37:29 -05003118void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3119 return fImpl->fDevice->onAsRgnClip(rgn);
3120}
3121
reed@android.com8a1c16f2008-12-17 15:59:43 +00003122int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3123int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003124
3125///////////////////////////////////////////////////////////////////////////////
3126
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003127static bool supported_for_raster_canvas(const SkImageInfo& info) {
3128 switch (info.alphaType()) {
3129 case kPremul_SkAlphaType:
3130 case kOpaque_SkAlphaType:
3131 break;
3132 default:
3133 return false;
3134 }
3135
3136 switch (info.colorType()) {
3137 case kAlpha_8_SkColorType:
3138 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003139 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003140 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003141 break;
3142 default:
3143 return false;
3144 }
3145
3146 return true;
3147}
3148
Mike Reed5df49342016-11-12 08:06:55 -06003149std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3150 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003151 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003152 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003153 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003154
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003155 SkBitmap bitmap;
3156 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003157 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003158 }
Mike Reed5df49342016-11-12 08:06:55 -06003159 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003160}
reedd5fa1a42014-08-09 11:08:05 -07003161
3162///////////////////////////////////////////////////////////////////////////////
3163
3164SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003165 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003166 : fCanvas(canvas)
3167 , fSaveCount(canvas->getSaveCount())
3168{
bsalomon49f085d2014-09-05 13:34:00 -07003169 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003170 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003171 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003172 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003173 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003174 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003175 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003176 canvas->save();
3177 }
mtklein6cfa73a2014-08-13 13:33:49 -07003178
bsalomon49f085d2014-09-05 13:34:00 -07003179 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003180 canvas->concat(*matrix);
3181 }
3182}
3183
3184SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3185 fCanvas->restoreToCount(fSaveCount);
3186}
reede8f30622016-03-23 18:59:25 -07003187
Florin Malitaee424ac2016-12-01 12:47:59 -05003188///////////////////////////////////////////////////////////////////////////////
3189
3190SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3191 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3192
Florin Malita439ace92016-12-02 12:05:41 -05003193SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3194 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3195
Florin Malitaee424ac2016-12-01 12:47:59 -05003196SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3197 (void)this->INHERITED::getSaveLayerStrategy(rec);
3198 return kNoLayer_SaveLayerStrategy;
3199}
3200
3201///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003202
reed73603f32016-09-20 08:42:38 -07003203static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3204static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3205static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3206static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3207static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3208static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003209
3210///////////////////////////////////////////////////////////////////////////////////////////////////
3211
3212SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3213 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3214 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3215 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3216 SkIPoint origin = dev->getOrigin();
3217 SkMatrix ctm = this->getTotalMatrix();
3218 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3219
3220 SkIRect clip = fMCRec->fRasterClip.getBounds();
3221 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003222 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003223 clip.setEmpty();
3224 }
3225
3226 fAllocator->updateHandle(handle, ctm, clip);
3227 return handle;
3228 }
3229 return nullptr;
3230}
3231
3232static bool install(SkBitmap* bm, const SkImageInfo& info,
3233 const SkRasterHandleAllocator::Rec& rec) {
3234 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3235 rec.fReleaseProc, rec.fReleaseCtx);
3236}
3237
3238SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3239 SkBitmap* bm) {
3240 SkRasterHandleAllocator::Rec rec;
3241 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3242 return nullptr;
3243 }
3244 return rec.fHandle;
3245}
3246
3247std::unique_ptr<SkCanvas>
3248SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3249 const SkImageInfo& info, const Rec* rec) {
3250 if (!alloc || !supported_for_raster_canvas(info)) {
3251 return nullptr;
3252 }
3253
3254 SkBitmap bm;
3255 Handle hndl;
3256
3257 if (rec) {
3258 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3259 } else {
3260 hndl = alloc->allocBitmap(info, &bm);
3261 }
3262 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3263}