blob: 8cef3353a24eab5ded70ec93b3ab86072705087c [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
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000834bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000835 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700836 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700837 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000838 return false;
839 }
840 weAllocated = true;
841 }
842
reedcf01e312015-05-23 19:14:51 -0700843 SkAutoPixmapUnlock unlocker;
844 if (bitmap->requestLock(&unlocker)) {
845 const SkPixmap& pm = unlocker.pixmap();
846 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}
875
reed96472de2014-12-10 09:53:42 -0800876bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000877 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000878 if (!device) {
879 return false;
880 }
mtkleinf0f14112014-12-12 08:46:25 -0800881
Matt Sarett03dd6d52017-01-23 12:15:09 -0500882 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000883}
884
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000885bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700886 SkAutoPixmapUnlock unlocker;
887 if (bitmap.requestLock(&unlocker)) {
888 const SkPixmap& pm = unlocker.pixmap();
889 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000890 }
891 return false;
892}
893
Matt Sarett03dd6d52017-01-23 12:15:09 -0500894bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000895 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000896 SkBaseDevice* device = this->getDevice();
897 if (!device) {
898 return false;
899 }
900
Matt Sarett03dd6d52017-01-23 12:15:09 -0500901 // This check gives us an early out and prevents generation ID churn on the surface.
902 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
903 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
904 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
905 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000906 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000907
Matt Sarett03dd6d52017-01-23 12:15:09 -0500908 // Tell our owning surface to bump its generation ID.
909 const bool completeOverwrite =
910 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700911 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700912
Matt Sarett03dd6d52017-01-23 12:15:09 -0500913 // This can still fail, most notably in the case of a invalid color type or alpha type
914 // conversion. We could pull those checks into this function and avoid the unnecessary
915 // generation ID bump. But then we would be performing those checks twice, since they
916 // are also necessary at the bitmap/pixmap entry points.
917 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000918}
reed@google.com51df9e32010-12-23 19:29:18 +0000919
reed@android.com8a1c16f2008-12-17 15:59:43 +0000920//////////////////////////////////////////////////////////////////////////////
921
reed2ff1fce2014-12-11 07:07:37 -0800922void SkCanvas::checkForDeferredSave() {
923 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800924 this->doSave();
925 }
926}
927
reedf0090cb2014-11-26 08:55:51 -0800928int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800929#ifdef SK_DEBUG
930 int count = 0;
931 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
932 for (;;) {
933 const MCRec* rec = (const MCRec*)iter.next();
934 if (!rec) {
935 break;
936 }
937 count += 1 + rec->fDeferredSaveCount;
938 }
939 SkASSERT(count == fSaveCount);
940#endif
941 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800942}
943
944int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800945 fSaveCount += 1;
946 fMCRec->fDeferredSaveCount += 1;
947 return this->getSaveCount() - 1; // return our prev value
948}
949
950void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800951 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700952
953 SkASSERT(fMCRec->fDeferredSaveCount > 0);
954 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800955 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800956}
957
958void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800959 if (fMCRec->fDeferredSaveCount > 0) {
960 SkASSERT(fSaveCount > 1);
961 fSaveCount -= 1;
962 fMCRec->fDeferredSaveCount -= 1;
963 } else {
964 // check for underflow
965 if (fMCStack.count() > 1) {
966 this->willRestore();
967 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700968 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800969 this->internalRestore();
970 this->didRestore();
971 }
reedf0090cb2014-11-26 08:55:51 -0800972 }
973}
974
975void SkCanvas::restoreToCount(int count) {
976 // sanity check
977 if (count < 1) {
978 count = 1;
979 }
mtkleinf0f14112014-12-12 08:46:25 -0800980
reedf0090cb2014-11-26 08:55:51 -0800981 int n = this->getSaveCount() - count;
982 for (int i = 0; i < n; ++i) {
983 this->restore();
984 }
985}
986
reed2ff1fce2014-12-11 07:07:37 -0800987void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700989 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000990 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000991
Mike Reedc42a1cd2017-02-14 14:25:14 -0500992 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000993}
994
reed4960eee2015-12-18 07:09:18 -0800995bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800996 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000997}
998
reed4960eee2015-12-18 07:09:18 -0800999bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001000 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001001 SkIRect clipBounds = this->getDeviceClipBounds();
1002 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001003 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001004 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001005
reed96e657d2015-03-10 17:30:07 -07001006 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1007
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001008 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001009 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001010 if (bounds && !imageFilter->canComputeFastBounds()) {
1011 bounds = nullptr;
1012 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001013 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001014 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001015 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001016 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001017
reed96e657d2015-03-10 17:30:07 -07001018 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001019 r.roundOut(&ir);
1020 // early exit if the layer's bounds are clipped out
1021 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001022 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -05001023 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -07001024 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001025 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001026 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001027 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028 }
1029 } else { // no user bounds, so just use the clip
1030 ir = clipBounds;
1031 }
reed180aec42015-03-11 10:39:04 -07001032 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001033
reed4960eee2015-12-18 07:09:18 -08001034 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001035 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -07001036 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001037 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001038 }
1039
1040 if (intersection) {
1041 *intersection = ir;
1042 }
1043 return true;
1044}
1045
reed4960eee2015-12-18 07:09:18 -08001046
reed4960eee2015-12-18 07:09:18 -08001047int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1048 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001049}
1050
reed70ee31b2015-12-10 13:44:45 -08001051int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001052 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1053}
1054
1055int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1056 SaveLayerRec rec(origRec);
1057 if (gIgnoreSaveLayerBounds) {
1058 rec.fBounds = nullptr;
1059 }
1060 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1061 fSaveCount += 1;
1062 this->internalSaveLayer(rec, strategy);
1063 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001064}
1065
reeda2217ef2016-07-20 06:04:34 -07001066void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001067 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001068 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001069 SkDraw draw;
1070 SkRasterClip rc;
1071 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1072 if (!dst->accessPixels(&draw.fDst)) {
1073 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001074 }
reeda2217ef2016-07-20 06:04:34 -07001075 draw.fMatrix = &SkMatrix::I();
1076 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001077
1078 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001079 if (filter) {
1080 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1081 }
reeda2217ef2016-07-20 06:04:34 -07001082
Mike Reedc42a1cd2017-02-14 14:25:14 -05001083 int x = src->getOrigin().x() - dstOrigin.x();
1084 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001085 auto special = src->snapSpecial();
1086 if (special) {
Mike Reeda1361362017-03-07 09:37:29 -05001087 dst->drawSpecial(special.get(), x, y, p);
reeda2217ef2016-07-20 06:04:34 -07001088 }
robertphillips7354a4b2015-12-16 05:08:27 -08001089}
reed70ee31b2015-12-10 13:44:45 -08001090
reed129ed1c2016-02-22 06:42:31 -08001091static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1092 const SkPaint* paint) {
1093 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1094 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001095 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001096 const bool hasImageFilter = paint && paint->getImageFilter();
1097
1098 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1099 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1100 // force to L32
1101 return SkImageInfo::MakeN32(w, h, alphaType);
1102 } else {
1103 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001104 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001105 }
1106}
1107
reed4960eee2015-12-18 07:09:18 -08001108void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1109 const SkRect* bounds = rec.fBounds;
1110 const SkPaint* paint = rec.fPaint;
1111 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1112
reed8c30a812016-04-20 16:36:51 -07001113 SkLazyPaint lazyP;
1114 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1115 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001116 SkMatrix remainder;
1117 SkSize scale;
1118 /*
1119 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1120 * but they do handle scaling. To accommodate this, we do the following:
1121 *
1122 * 1. Stash off the current CTM
1123 * 2. Decompose the CTM into SCALE and REMAINDER
1124 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1125 * contains the REMAINDER
1126 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1127 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1128 * of the original imagefilter, and draw that (via drawSprite)
1129 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1130 *
1131 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1132 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1133 */
reed96a04f32016-04-25 09:25:15 -07001134 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001135 stashedMatrix.decomposeScale(&scale, &remainder))
1136 {
1137 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1138 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1139 SkPaint* p = lazyP.set(*paint);
1140 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1141 SkFilterQuality::kLow_SkFilterQuality,
1142 sk_ref_sp(imageFilter)));
1143 imageFilter = p->getImageFilter();
1144 paint = p;
1145 }
reed8c30a812016-04-20 16:36:51 -07001146
junov@chromium.orga907ac32012-02-24 21:54:07 +00001147 // do this before we create the layer. We don't call the public save() since
1148 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001149 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001150
junov@chromium.orga907ac32012-02-24 21:54:07 +00001151 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001152 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001153 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001154 }
1155
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001156 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1157 // the clipRectBounds() call above?
1158 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001159 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001160 }
1161
reed4960eee2015-12-18 07:09:18 -08001162 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001163 SkPixelGeometry geo = fProps.pixelGeometry();
1164 if (paint) {
reed76033be2015-03-14 10:54:31 -07001165 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001166 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001167 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001168 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001169 }
1170 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001171
robertphillips5139e502016-07-19 05:10:40 -07001172 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001173 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001174 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001175 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001176 }
reedb2db8982014-11-13 12:41:02 -08001177
robertphillips5139e502016-07-19 05:10:40 -07001178 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001179 paint);
1180
Hal Canary704cd322016-11-07 14:13:52 -05001181 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001182 {
reed70ee31b2015-12-10 13:44:45 -08001183 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001184 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001185 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001186 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001187 preserveLCDText,
1188 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001189 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1190 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001191 return;
reed61f501f2015-04-29 08:34:00 -07001192 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001193 }
Hal Canary704cd322016-11-07 14:13:52 -05001194 DeviceCM* layer =
Mike Reeda1361362017-03-07 09:37:29 -05001195 new DeviceCM(newDevice.get(), paint, this, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196
Mike Reedb43a3e02017-02-11 10:18:58 -05001197 // only have a "next" if this new layer doesn't affect the clip (rare)
1198 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001199 fMCRec->fLayer = layer;
1200 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001201
Mike Reedc61abee2017-02-28 17:45:27 -05001202 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001203 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001204 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001205 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001206
Mike Reedc42a1cd2017-02-14 14:25:14 -05001207 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1208
1209 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1210 if (layer->fNext) {
1211 // need to punch a hole in the previous device, so we don't draw there, given that
1212 // the new top-layer will allow drawing to happen "below" it.
1213 SkRegion hole(ir);
1214 do {
1215 layer = layer->fNext;
1216 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1217 } while (layer->fNext);
1218 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001219}
1220
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001221int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001222 if (0xFF == alpha) {
1223 return this->saveLayer(bounds, nullptr);
1224 } else {
1225 SkPaint tmpPaint;
1226 tmpPaint.setAlpha(alpha);
1227 return this->saveLayer(bounds, &tmpPaint);
1228 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001229}
1230
reed@android.com8a1c16f2008-12-17 15:59:43 +00001231void SkCanvas::internalRestore() {
1232 SkASSERT(fMCStack.count() != 0);
1233
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001234 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001235 DeviceCM* layer = fMCRec->fLayer; // may be null
1236 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001237 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238
1239 // now do the normal restore()
1240 fMCRec->~MCRec(); // balanced in save()
1241 fMCStack.pop_back();
1242 fMCRec = (MCRec*)fMCStack.back();
1243
Mike Reedc42a1cd2017-02-14 14:25:14 -05001244 if (fMCRec) {
1245 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1246 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001247
reed@android.com8a1c16f2008-12-17 15:59:43 +00001248 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1249 since if we're being recorded, we don't want to record this (the
1250 recorder will have already recorded the restore).
1251 */
bsalomon49f085d2014-09-05 13:34:00 -07001252 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001253 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001254 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001255 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001256 // restore what we smashed in internalSaveLayer
1257 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001258 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001259 delete layer;
reedb679ca82015-04-07 04:40:48 -07001260 } else {
1261 // we're at the root
reeda499f902015-05-01 09:34:31 -07001262 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001263 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001264 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001266 }
msarettfbfa2582016-08-12 08:29:08 -07001267
1268 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001269 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001270 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1271 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272}
1273
reede8f30622016-03-23 18:59:25 -07001274sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001275 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001276 props = &fProps;
1277 }
1278 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001279}
1280
reede8f30622016-03-23 18:59:25 -07001281sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001282 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001283 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001284}
1285
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001286SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001287 return this->onImageInfo();
1288}
1289
1290SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001291 SkBaseDevice* dev = this->getDevice();
1292 if (dev) {
1293 return dev->imageInfo();
1294 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001295 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001296 }
1297}
1298
brianosman898235c2016-04-06 07:38:23 -07001299bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001300 return this->onGetProps(props);
1301}
1302
1303bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001304 SkBaseDevice* dev = this->getDevice();
1305 if (dev) {
1306 if (props) {
1307 *props = fProps;
1308 }
1309 return true;
1310 } else {
1311 return false;
1312 }
1313}
1314
reed6ceeebd2016-03-09 14:26:26 -08001315bool SkCanvas::peekPixels(SkPixmap* pmap) {
1316 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001317}
1318
reed884e97c2015-05-26 11:31:54 -07001319bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001320 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001321 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001322}
1323
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001324void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001325 SkPixmap pmap;
1326 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001327 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001328 }
1329 if (info) {
1330 *info = pmap.info();
1331 }
1332 if (rowBytes) {
1333 *rowBytes = pmap.rowBytes();
1334 }
1335 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001336 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001337 }
reed884e97c2015-05-26 11:31:54 -07001338 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001339}
1340
reed884e97c2015-05-26 11:31:54 -07001341bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001342 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001343 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001344}
1345
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001347
reed7503d602016-07-15 14:23:29 -07001348void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001349 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001350 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001351 paint = &tmp;
1352 }
reed@google.com4b226022011-01-11 18:32:13 +00001353
reed@google.com8926b162012-03-23 15:36:36 +00001354 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001355
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001357 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001358 paint = &looper.paint();
1359 SkImageFilter* filter = paint->getImageFilter();
1360 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001361 if (filter) {
1362 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1363 if (specialImage) {
Mike Reeda1361362017-03-07 09:37:29 -05001364 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint);
Robert Phillips833dcf42016-11-18 08:44:13 -05001365 }
reed@google.com76dd2772012-01-05 21:15:07 +00001366 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001367 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001368 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001369 }
reeda2217ef2016-07-20 06:04:34 -07001370
reed@google.com4e2b3d32011-04-07 14:18:59 +00001371 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372}
1373
reed32704672015-12-16 08:27:10 -08001374/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001375
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001376void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001377 if (dx || dy) {
1378 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001379 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001380
reedfe69b502016-09-12 06:31:48 -07001381 // Translate shouldn't affect the is-scale-translateness of the matrix.
1382 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001383
Mike Reedc42a1cd2017-02-14 14:25:14 -05001384 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001385
reedfe69b502016-09-12 06:31:48 -07001386 this->didTranslate(dx,dy);
1387 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388}
1389
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001390void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001391 SkMatrix m;
1392 m.setScale(sx, sy);
1393 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001394}
1395
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001396void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001397 SkMatrix m;
1398 m.setRotate(degrees);
1399 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001400}
1401
bungeman7438bfc2016-07-12 15:01:19 -07001402void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1403 SkMatrix m;
1404 m.setRotate(degrees, px, py);
1405 this->concat(m);
1406}
1407
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001408void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001409 SkMatrix m;
1410 m.setSkew(sx, sy);
1411 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001412}
1413
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001414void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001415 if (matrix.isIdentity()) {
1416 return;
1417 }
1418
reed2ff1fce2014-12-11 07:07:37 -08001419 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001420 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001421 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001422
Mike Reed7627fa52017-02-08 10:07:53 -05001423 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001424
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001425 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001426}
1427
reed8c30a812016-04-20 16:36:51 -07001428void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001429 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001430 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001431
Mike Reedc42a1cd2017-02-14 14:25:14 -05001432 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001433}
1434
1435void SkCanvas::setMatrix(const SkMatrix& matrix) {
1436 this->checkForDeferredSave();
1437 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001438 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439}
1440
reed@android.com8a1c16f2008-12-17 15:59:43 +00001441void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001442 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001443}
1444
vjiaoblack95302da2016-07-21 10:25:54 -07001445#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001446void SkCanvas::translateZ(SkScalar z) {
1447 this->checkForDeferredSave();
1448 this->fMCRec->fCurDrawDepth += z;
1449 this->didTranslateZ(z);
1450}
1451
1452SkScalar SkCanvas::getZ() const {
1453 return this->fMCRec->fCurDrawDepth;
1454}
1455
vjiaoblack95302da2016-07-21 10:25:54 -07001456void SkCanvas::setLights(sk_sp<SkLights> lights) {
1457 this->fLights = lights;
1458}
1459
1460sk_sp<SkLights> SkCanvas::getLights() const {
1461 return this->fLights;
1462}
1463#endif
1464
reed@android.com8a1c16f2008-12-17 15:59:43 +00001465//////////////////////////////////////////////////////////////////////////////
1466
Mike Reedc1f77742016-12-09 09:00:50 -05001467void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001468 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001469 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1470 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001471}
1472
Mike Reedc1f77742016-12-09 09:00:50 -05001473void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001474 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001475
Mike Reed7627fa52017-02-08 10:07:53 -05001476 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001477
reedc64eff52015-11-21 12:39:45 -08001478 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001479 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1480 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001481 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482}
1483
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001484void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1485 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001486 if (fClipRestrictionRect.isEmpty()) {
1487 // we notify the device, but we *dont* resolve deferred saves (since we're just
1488 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001489 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001490 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001491 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001492 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001493 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001494 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001495 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1496 }
1497}
1498
Mike Reedc1f77742016-12-09 09:00:50 -05001499void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001500 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001501 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001502 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001503 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1504 } else {
1505 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001506 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001507}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001508
Mike Reedc1f77742016-12-09 09:00:50 -05001509void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001510 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001511
Brian Salomona3b45d42016-10-03 11:36:16 -04001512 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001513
Mike Reed7627fa52017-02-08 10:07:53 -05001514 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001515
Brian Salomona3b45d42016-10-03 11:36:16 -04001516 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1517 isAA);
1518 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001519}
1520
Mike Reedc1f77742016-12-09 09:00:50 -05001521void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001522 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001523 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001524
1525 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1526 SkRect r;
1527 if (path.isRect(&r)) {
1528 this->onClipRect(r, op, edgeStyle);
1529 return;
1530 }
1531 SkRRect rrect;
1532 if (path.isOval(&r)) {
1533 rrect.setOval(r);
1534 this->onClipRRect(rrect, op, edgeStyle);
1535 return;
1536 }
1537 if (path.isRRect(&rrect)) {
1538 this->onClipRRect(rrect, op, edgeStyle);
1539 return;
1540 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001541 }
robertphillips39f05382015-11-24 09:30:12 -08001542
1543 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001544}
1545
Mike Reedc1f77742016-12-09 09:00:50 -05001546void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001547 AutoValidateClip avc(this);
1548
Brian Salomona3b45d42016-10-03 11:36:16 -04001549 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001550
Mike Reed7627fa52017-02-08 10:07:53 -05001551 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001552
Brian Salomona3b45d42016-10-03 11:36:16 -04001553 const SkPath* rasterClipPath = &path;
1554 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001555 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1556 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001557 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558}
1559
Mike Reedc1f77742016-12-09 09:00:50 -05001560void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001561 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001562 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001563}
1564
Mike Reedc1f77742016-12-09 09:00:50 -05001565void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001566 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001567
reed@google.com5c3d1472011-02-22 19:12:23 +00001568 AutoValidateClip avc(this);
1569
reed73603f32016-09-20 08:42:38 -07001570 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001571 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001572}
1573
reed@google.com819c9212011-02-23 18:56:55 +00001574#ifdef SK_DEBUG
1575void SkCanvas::validateClip() const {
1576 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001577 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001578 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001579 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001580 return;
1581 }
reed@google.com819c9212011-02-23 18:56:55 +00001582}
1583#endif
1584
Mike Reed93b1b4f2017-04-05 16:21:47 -04001585#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP
Mike Reed8310f0e2017-03-08 21:42:37 +00001586void SkCanvas::replayClips(ClipVisitor* visitor) const {
1587#if 0
1588 SkClipStack::B2TIter iter(*fClipStack);
1589 const SkClipStack::Element* element;
1590
1591 while ((element = iter.next()) != nullptr) {
1592 element->replay(visitor);
1593 }
1594#endif
1595}
Mike Reed93b1b4f2017-04-05 16:21:47 -04001596#endif
Mike Reed8310f0e2017-03-08 21:42:37 +00001597
Mike Reeda1361362017-03-07 09:37:29 -05001598bool SkCanvas::androidFramework_isClipAA() const {
1599 bool containsAA = false;
1600
1601 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1602
1603 return containsAA;
1604}
1605
1606class RgnAccumulator {
1607 SkRegion* fRgn;
1608public:
1609 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1610 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1611 SkIPoint origin = device->getOrigin();
1612 if (origin.x() | origin.y()) {
1613 rgn->translate(origin.x(), origin.y());
1614 }
1615 fRgn->op(*rgn, SkRegion::kUnion_Op);
1616 }
1617};
1618
1619void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1620 RgnAccumulator accum(rgn);
1621 SkRegion tmp;
1622
1623 rgn->setEmpty();
1624 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001625}
1626
reed@google.com5c3d1472011-02-22 19:12:23 +00001627///////////////////////////////////////////////////////////////////////////////
1628
reed@google.com754de5f2014-02-24 19:38:20 +00001629bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001630 return fMCRec->fRasterClip.isEmpty();
1631
1632 // TODO: should we only use the conservative answer in a recording canvas?
1633#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001634 SkBaseDevice* dev = this->getTopDevice();
1635 // if no device we return true
1636 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001637#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001638}
1639
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001640bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001641 SkBaseDevice* dev = this->getTopDevice();
1642 // if no device we return false
1643 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001644}
1645
msarettfbfa2582016-08-12 08:29:08 -07001646static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1647#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1648 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1649 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1650 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1651 return 0xF != _mm_movemask_ps(mask);
1652#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1653 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1654 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1655 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1656 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1657#else
1658 SkRect devRectAsRect;
1659 SkRect devClipAsRect;
1660 devRect.store(&devRectAsRect.fLeft);
1661 devClip.store(&devClipAsRect.fLeft);
1662 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1663#endif
1664}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001665
msarettfbfa2582016-08-12 08:29:08 -07001666// It's important for this function to not be inlined. Otherwise the compiler will share code
1667// between the fast path and the slow path, resulting in two slow paths.
1668static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1669 const SkMatrix& matrix) {
1670 SkRect deviceRect;
1671 matrix.mapRect(&deviceRect, src);
1672 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1673}
1674
1675bool SkCanvas::quickReject(const SkRect& src) const {
1676#ifdef SK_DEBUG
1677 // Verify that fDeviceClipBounds are set properly.
1678 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001679 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001680 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001681 } else {
msarettfbfa2582016-08-12 08:29:08 -07001682 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001683 }
msarettfbfa2582016-08-12 08:29:08 -07001684
msarett9637ea92016-08-18 14:03:30 -07001685 // Verify that fIsScaleTranslate is set properly.
1686 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001687#endif
1688
msarett9637ea92016-08-18 14:03:30 -07001689 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001690 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1691 }
1692
1693 // We inline the implementation of mapScaleTranslate() for the fast path.
1694 float sx = fMCRec->fMatrix.getScaleX();
1695 float sy = fMCRec->fMatrix.getScaleY();
1696 float tx = fMCRec->fMatrix.getTranslateX();
1697 float ty = fMCRec->fMatrix.getTranslateY();
1698 Sk4f scale(sx, sy, sx, sy);
1699 Sk4f trans(tx, ty, tx, ty);
1700
1701 // Apply matrix.
1702 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1703
1704 // Make sure left < right, top < bottom.
1705 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1706 Sk4f min = Sk4f::Min(ltrb, rblt);
1707 Sk4f max = Sk4f::Max(ltrb, rblt);
1708 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1709 // ARM this sequence generates the fastest (a single instruction).
1710 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1711
1712 // Check if the device rect is NaN or outside the clip.
1713 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714}
1715
reed@google.com3b3e8952012-08-16 20:53:31 +00001716bool SkCanvas::quickReject(const SkPath& path) const {
1717 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001718}
1719
Mike Reed42e8c532017-01-23 14:09:13 -05001720SkRect SkCanvas::onGetLocalClipBounds() const {
1721 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001722 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001723 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001724 }
1725
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001726 SkMatrix inverse;
1727 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001728 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001729 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001730 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001731
Mike Reed42e8c532017-01-23 14:09:13 -05001732 SkRect bounds;
1733 SkRect r;
1734 // adjust it outwards in case we are antialiasing
1735 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001736
Mike Reed42e8c532017-01-23 14:09:13 -05001737 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1738 ibounds.fRight + inset, ibounds.fBottom + inset);
1739 inverse.mapRect(&bounds, r);
1740 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001741}
1742
Mike Reed42e8c532017-01-23 14:09:13 -05001743SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001744 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001745}
1746
reed@android.com8a1c16f2008-12-17 15:59:43 +00001747const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001748 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001749}
1750
Brian Osman11052242016-10-27 14:47:55 -04001751GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001752 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001753 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001754}
1755
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001756GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001757 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001758 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001759}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001760
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001761void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1762 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001763 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001764 if (outer.isEmpty()) {
1765 return;
1766 }
1767 if (inner.isEmpty()) {
1768 this->drawRRect(outer, paint);
1769 return;
1770 }
1771
1772 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001773 // be able to return ...
1774 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001775 //
1776 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001777 if (!outer.getBounds().contains(inner.getBounds())) {
1778 return;
1779 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001780
1781 this->onDrawDRRect(outer, inner, paint);
1782}
1783
reed41af9662015-01-05 07:49:08 -08001784// These need to stop being virtual -- clients need to override the onDraw... versions
1785
1786void SkCanvas::drawPaint(const SkPaint& paint) {
1787 this->onDrawPaint(paint);
1788}
1789
1790void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1791 this->onDrawRect(r, paint);
1792}
1793
msarettdca352e2016-08-26 06:37:45 -07001794void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1795 if (region.isEmpty()) {
1796 return;
1797 }
1798
1799 if (region.isRect()) {
1800 return this->drawIRect(region.getBounds(), paint);
1801 }
1802
1803 this->onDrawRegion(region, paint);
1804}
1805
reed41af9662015-01-05 07:49:08 -08001806void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1807 this->onDrawOval(r, paint);
1808}
1809
1810void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1811 this->onDrawRRect(rrect, paint);
1812}
1813
1814void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1815 this->onDrawPoints(mode, count, pts, paint);
1816}
1817
Mike Reede88a1cb2017-03-17 09:50:46 -04001818void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1819 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001820 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001821 this->onDrawVerticesObject(vertices.get(), mode, paint);
1822}
1823
1824void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1825 RETURN_ON_NULL(vertices);
1826 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001827}
1828
1829void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1830 this->onDrawPath(path, paint);
1831}
1832
reeda85d4d02015-05-06 12:56:48 -07001833void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001834 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001835 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001836}
1837
reede47829b2015-08-06 10:02:53 -07001838void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1839 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001840 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001841 if (dst.isEmpty() || src.isEmpty()) {
1842 return;
1843 }
1844 this->onDrawImageRect(image, &src, dst, paint, constraint);
1845}
reed41af9662015-01-05 07:49:08 -08001846
reed84984ef2015-07-17 07:09:43 -07001847void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1848 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001849 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001850 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001851}
1852
reede47829b2015-08-06 10:02:53 -07001853void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1854 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001855 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001856 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1857 constraint);
1858}
reede47829b2015-08-06 10:02:53 -07001859
reed4c21dc52015-06-25 12:32:03 -07001860void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1861 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001862 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001863 if (dst.isEmpty()) {
1864 return;
1865 }
msarett552bca92016-08-03 06:53:26 -07001866 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1867 this->onDrawImageNine(image, center, dst, paint);
1868 } else {
reede47829b2015-08-06 10:02:53 -07001869 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001870 }
reed4c21dc52015-06-25 12:32:03 -07001871}
1872
msarett16882062016-08-16 09:31:08 -07001873void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1874 const SkPaint* paint) {
1875 RETURN_ON_NULL(image);
1876 if (dst.isEmpty()) {
1877 return;
1878 }
msarett71df2d72016-09-30 12:41:42 -07001879
1880 SkIRect bounds;
1881 Lattice latticePlusBounds = lattice;
1882 if (!latticePlusBounds.fBounds) {
1883 bounds = SkIRect::MakeWH(image->width(), image->height());
1884 latticePlusBounds.fBounds = &bounds;
1885 }
1886
1887 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1888 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001889 } else {
1890 this->drawImageRect(image, dst, paint);
1891 }
1892}
1893
reed41af9662015-01-05 07:49:08 -08001894void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001895 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001896 return;
1897 }
reed41af9662015-01-05 07:49:08 -08001898 this->onDrawBitmap(bitmap, dx, dy, paint);
1899}
1900
reede47829b2015-08-06 10:02:53 -07001901void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001902 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001903 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001904 return;
1905 }
reede47829b2015-08-06 10:02:53 -07001906 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001907}
1908
reed84984ef2015-07-17 07:09:43 -07001909void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1910 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001911 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001912}
1913
reede47829b2015-08-06 10:02:53 -07001914void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1915 SrcRectConstraint constraint) {
1916 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1917 constraint);
1918}
reede47829b2015-08-06 10:02:53 -07001919
reed41af9662015-01-05 07:49:08 -08001920void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1921 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001922 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001923 return;
1924 }
msarett552bca92016-08-03 06:53:26 -07001925 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1926 this->onDrawBitmapNine(bitmap, center, dst, paint);
1927 } else {
reeda5517e22015-07-14 10:54:12 -07001928 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001929 }
reed41af9662015-01-05 07:49:08 -08001930}
1931
msarettc573a402016-08-02 08:05:56 -07001932void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1933 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001934 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001935 return;
1936 }
msarett71df2d72016-09-30 12:41:42 -07001937
1938 SkIRect bounds;
1939 Lattice latticePlusBounds = lattice;
1940 if (!latticePlusBounds.fBounds) {
1941 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1942 latticePlusBounds.fBounds = &bounds;
1943 }
1944
1945 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1946 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001947 } else {
msarett16882062016-08-16 09:31:08 -07001948 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001949 }
msarettc573a402016-08-02 08:05:56 -07001950}
1951
reed71c3c762015-06-24 10:29:17 -07001952void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001953 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001954 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001955 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001956 if (count <= 0) {
1957 return;
1958 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001959 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001960 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001961 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001962}
1963
reedf70b5312016-03-04 16:36:20 -08001964void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1965 if (key) {
1966 this->onDrawAnnotation(rect, key, value);
1967 }
1968}
1969
reede47829b2015-08-06 10:02:53 -07001970void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1971 const SkPaint* paint, SrcRectConstraint constraint) {
1972 if (src) {
1973 this->drawImageRect(image, *src, dst, paint, constraint);
1974 } else {
1975 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1976 dst, paint, constraint);
1977 }
1978}
1979void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1980 const SkPaint* paint, SrcRectConstraint constraint) {
1981 if (src) {
1982 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1983 } else {
1984 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1985 dst, paint, constraint);
1986 }
1987}
1988
tomhudsoncb3bd182016-05-18 07:24:16 -07001989void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1990 SkIRect layer_bounds = this->getTopLayerBounds();
1991 if (matrix) {
1992 *matrix = this->getTotalMatrix();
1993 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1994 }
1995 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001996 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001997 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1998 }
1999}
2000
reed@android.com8a1c16f2008-12-17 15:59:43 +00002001//////////////////////////////////////////////////////////////////////////////
2002// These are the virtual drawing methods
2003//////////////////////////////////////////////////////////////////////////////
2004
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002005void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002006 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002007 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2008 }
2009}
2010
reed41af9662015-01-05 07:49:08 -08002011void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002012 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002013 this->internalDrawPaint(paint);
2014}
2015
2016void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002017 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018
2019 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002020 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002021 }
2022
reed@google.com4e2b3d32011-04-07 14:18:59 +00002023 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002024}
2025
reed41af9662015-01-05 07:49:08 -08002026void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2027 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002028 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002029 if ((long)count <= 0) {
2030 return;
2031 }
2032
Mike Reed822128b2017-02-28 16:41:03 -05002033 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002034 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002035 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002036 // special-case 2 points (common for drawing a single line)
2037 if (2 == count) {
2038 r.set(pts[0], pts[1]);
2039 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002040 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002041 }
Mike Reed822128b2017-02-28 16:41:03 -05002042 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002043 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2044 return;
2045 }
2046 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002047 }
reed@google.coma584aed2012-05-16 14:06:02 +00002048
halcanary96fcdcc2015-08-27 07:41:13 -07002049 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002050
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002051 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002052
reed@android.com8a1c16f2008-12-17 15:59:43 +00002053 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002054 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002055 }
reed@google.com4b226022011-01-11 18:32:13 +00002056
reed@google.com4e2b3d32011-04-07 14:18:59 +00002057 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002058}
2059
reed4a167172016-08-18 17:15:25 -07002060static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2061 return ((intptr_t)paint.getImageFilter() |
2062#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2063 (intptr_t)canvas->getDrawFilter() |
2064#endif
2065 (intptr_t)paint.getLooper() ) != 0;
2066}
2067
reed41af9662015-01-05 07:49:08 -08002068void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002069 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002070 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002071 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2072 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2073 SkRect tmp(r);
2074 tmp.sort();
2075
Mike Reed822128b2017-02-28 16:41:03 -05002076 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002077 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2078 return;
2079 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002080 }
reed@google.com4b226022011-01-11 18:32:13 +00002081
reed4a167172016-08-18 17:15:25 -07002082 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002083 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002084
reed4a167172016-08-18 17:15:25 -07002085 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002086 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002087 }
2088
2089 LOOPER_END
2090 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002091 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002092 SkDrawIter iter(this);
2093 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002094 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002095 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002096 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002097}
2098
msarett44df6512016-08-25 13:54:30 -07002099void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002100 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002101 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002102 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002103 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2104 return;
2105 }
msarett44df6512016-08-25 13:54:30 -07002106 }
2107
Mike Reed822128b2017-02-28 16:41:03 -05002108 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002109
2110 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002111 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002112 }
2113
2114 LOOPER_END
2115}
2116
reed41af9662015-01-05 07:49:08 -08002117void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002118 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002119 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002120 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002121 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2122 return;
2123 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002124 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002125
Mike Reed822128b2017-02-28 16:41:03 -05002126 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002127
2128 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002129 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002130 }
2131
2132 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002133}
2134
bsalomonac3aa242016-08-19 11:25:19 -07002135void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2136 SkScalar sweepAngle, bool useCenter,
2137 const SkPaint& paint) {
2138 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002139 if (paint.canComputeFastBounds()) {
2140 SkRect storage;
2141 // Note we're using the entire oval as the bounds.
2142 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2143 return;
2144 }
bsalomonac3aa242016-08-19 11:25:19 -07002145 }
2146
Mike Reed822128b2017-02-28 16:41:03 -05002147 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002148
2149 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002150 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002151 }
2152
2153 LOOPER_END
2154}
2155
reed41af9662015-01-05 07:49:08 -08002156void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002157 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002158 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002159 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002160 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2161 return;
2162 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002163 }
2164
2165 if (rrect.isRect()) {
2166 // call the non-virtual version
2167 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002168 return;
2169 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002170 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002171 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2172 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002173 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002174
Mike Reed822128b2017-02-28 16:41:03 -05002175 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002176
2177 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002178 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002179 }
2180
2181 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002182}
2183
Mike Reed822128b2017-02-28 16:41:03 -05002184void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002185 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002186 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002187 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2188 return;
2189 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002190 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002191
Mike Reed822128b2017-02-28 16:41:03 -05002192 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002193
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002194 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002195 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002196 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002197
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002198 LOOPER_END
2199}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002200
reed41af9662015-01-05 07:49:08 -08002201void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002202 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002203 if (!path.isFinite()) {
2204 return;
2205 }
2206
Mike Reed822128b2017-02-28 16:41:03 -05002207 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002208 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002209 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002210 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2211 return;
2212 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002213 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002214
Mike Reed822128b2017-02-28 16:41:03 -05002215 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002216 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002217 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002218 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002219 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002220 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002221
Mike Reed822128b2017-02-28 16:41:03 -05002222 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002223
2224 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002225 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002226 }
2227
reed@google.com4e2b3d32011-04-07 14:18:59 +00002228 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002229}
2230
reed262a71b2015-12-05 13:07:27 -08002231bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002232 if (!paint.getImageFilter()) {
2233 return false;
2234 }
2235
2236 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002237 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002238 return false;
2239 }
2240
2241 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2242 // Once we can filter and the filter will return a result larger than itself, we should be
2243 // able to remove this constraint.
2244 // skbug.com/4526
2245 //
2246 SkPoint pt;
2247 ctm.mapXY(x, y, &pt);
2248 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2249 return ir.contains(fMCRec->fRasterClip.getBounds());
2250}
2251
reeda85d4d02015-05-06 12:56:48 -07002252void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002253 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002254 SkRect bounds = SkRect::MakeXYWH(x, y,
2255 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002256 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002257 SkRect tmp = bounds;
2258 if (paint) {
2259 paint->computeFastBounds(tmp, &tmp);
2260 }
2261 if (this->quickReject(tmp)) {
2262 return;
2263 }
reeda85d4d02015-05-06 12:56:48 -07002264 }
halcanary9d524f22016-03-29 09:03:52 -07002265
reeda85d4d02015-05-06 12:56:48 -07002266 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002267 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002268 paint = lazy.init();
2269 }
reed262a71b2015-12-05 13:07:27 -08002270
reeda2217ef2016-07-20 06:04:34 -07002271 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002272 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2273 *paint);
2274 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002275 special = this->getDevice()->makeSpecial(image);
2276 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002277 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002278 }
2279 }
2280
reed262a71b2015-12-05 13:07:27 -08002281 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2282
reeda85d4d02015-05-06 12:56:48 -07002283 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002284 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002285 if (special) {
2286 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002287 iter.fDevice->ctm().mapXY(x, y, &pt);
2288 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002289 SkScalarRoundToInt(pt.fX),
2290 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002291 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002292 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002293 }
reeda85d4d02015-05-06 12:56:48 -07002294 }
halcanary9d524f22016-03-29 09:03:52 -07002295
reeda85d4d02015-05-06 12:56:48 -07002296 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002297}
2298
reed41af9662015-01-05 07:49:08 -08002299void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002300 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002301 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002302 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002303 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002304 if (paint) {
2305 paint->computeFastBounds(dst, &storage);
2306 }
2307 if (this->quickReject(storage)) {
2308 return;
2309 }
reeda85d4d02015-05-06 12:56:48 -07002310 }
2311 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002312 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002313 paint = lazy.init();
2314 }
halcanary9d524f22016-03-29 09:03:52 -07002315
senorblancoc41e7e12015-12-07 12:51:30 -08002316 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002317 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002318
reeda85d4d02015-05-06 12:56:48 -07002319 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002320 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002321 }
halcanary9d524f22016-03-29 09:03:52 -07002322
reeda85d4d02015-05-06 12:56:48 -07002323 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002324}
2325
reed41af9662015-01-05 07:49:08 -08002326void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002327 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328 SkDEBUGCODE(bitmap.validate();)
2329
reed33366972015-10-08 09:22:02 -07002330 if (bitmap.drawsNothing()) {
2331 return;
2332 }
2333
2334 SkLazyPaint lazy;
2335 if (nullptr == paint) {
2336 paint = lazy.init();
2337 }
2338
Mike Reed822128b2017-02-28 16:41:03 -05002339 SkRect bounds;
2340 bitmap.getBounds(&bounds);
2341 bounds.offset(x, y);
2342 bool canFastBounds = paint->canComputeFastBounds();
2343 if (canFastBounds) {
2344 SkRect storage;
2345 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002346 return;
2347 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002348 }
reed@google.com4b226022011-01-11 18:32:13 +00002349
reeda2217ef2016-07-20 06:04:34 -07002350 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002351 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2352 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002353 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002354 special = this->getDevice()->makeSpecial(bitmap);
2355 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002356 drawAsSprite = false;
2357 }
2358 }
2359
Mike Reed822128b2017-02-28 16:41:03 -05002360 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2361
2362 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002363
2364 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002365 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002366 if (special) {
reed262a71b2015-12-05 13:07:27 -08002367 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002368 iter.fDevice->ctm().mapXY(x, y, &pt);
2369 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002370 SkScalarRoundToInt(pt.fX),
2371 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002372 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002373 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002374 }
reed33366972015-10-08 09:22:02 -07002375 }
msarettfbfa2582016-08-12 08:29:08 -07002376
reed33366972015-10-08 09:22:02 -07002377 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002378}
2379
reed@google.com9987ec32011-09-07 11:57:52 +00002380// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002381void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002382 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002383 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002384 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002385 return;
2386 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002387
halcanary96fcdcc2015-08-27 07:41:13 -07002388 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002389 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002390 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2391 return;
2392 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002393 }
reed@google.com3d608122011-11-21 15:16:16 +00002394
reed@google.com33535f32012-09-25 15:37:50 +00002395 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002396 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002397 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002398 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002399
senorblancoc41e7e12015-12-07 12:51:30 -08002400 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002401 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002402
reed@google.com33535f32012-09-25 15:37:50 +00002403 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002404 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002405 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002406
reed@google.com33535f32012-09-25 15:37:50 +00002407 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002408}
2409
reed41af9662015-01-05 07:49:08 -08002410void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002411 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002412 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002413 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002414 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002415}
2416
reed4c21dc52015-06-25 12:32:03 -07002417void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2418 const SkPaint* paint) {
2419 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002420
halcanary96fcdcc2015-08-27 07:41:13 -07002421 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002422 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002423 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2424 return;
2425 }
reed@google.com3d608122011-11-21 15:16:16 +00002426 }
halcanary9d524f22016-03-29 09:03:52 -07002427
reed4c21dc52015-06-25 12:32:03 -07002428 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002429 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002430 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002431 }
halcanary9d524f22016-03-29 09:03:52 -07002432
senorblancoc41e7e12015-12-07 12:51:30 -08002433 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002434
reed4c21dc52015-06-25 12:32:03 -07002435 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002436 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002437 }
halcanary9d524f22016-03-29 09:03:52 -07002438
reed4c21dc52015-06-25 12:32:03 -07002439 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002440}
2441
reed41af9662015-01-05 07:49:08 -08002442void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2443 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002444 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002445 SkDEBUGCODE(bitmap.validate();)
2446
halcanary96fcdcc2015-08-27 07:41:13 -07002447 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002448 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002449 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2450 return;
2451 }
reed4c21dc52015-06-25 12:32:03 -07002452 }
halcanary9d524f22016-03-29 09:03:52 -07002453
reed4c21dc52015-06-25 12:32:03 -07002454 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002455 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002456 paint = lazy.init();
2457 }
halcanary9d524f22016-03-29 09:03:52 -07002458
senorblancoc41e7e12015-12-07 12:51:30 -08002459 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002460
reed4c21dc52015-06-25 12:32:03 -07002461 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002462 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002463 }
halcanary9d524f22016-03-29 09:03:52 -07002464
reed4c21dc52015-06-25 12:32:03 -07002465 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002466}
2467
msarett16882062016-08-16 09:31:08 -07002468void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2469 const SkPaint* paint) {
2470 if (nullptr == paint || paint->canComputeFastBounds()) {
2471 SkRect storage;
2472 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2473 return;
2474 }
2475 }
2476
2477 SkLazyPaint lazy;
2478 if (nullptr == paint) {
2479 paint = lazy.init();
2480 }
2481
2482 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2483
2484 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002485 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002486 }
2487
2488 LOOPER_END
2489}
2490
2491void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2492 const SkRect& dst, const SkPaint* paint) {
2493 if (nullptr == paint || paint->canComputeFastBounds()) {
2494 SkRect storage;
2495 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2496 return;
2497 }
2498 }
2499
2500 SkLazyPaint lazy;
2501 if (nullptr == paint) {
2502 paint = lazy.init();
2503 }
2504
2505 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2506
2507 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002508 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002509 }
2510
2511 LOOPER_END
2512}
2513
reed@google.comf67e4cf2011-03-15 20:56:58 +00002514class SkDeviceFilteredPaint {
2515public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002516 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002517 uint32_t filteredFlags = device->filterTextFlags(paint);
2518 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002519 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002520 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002521 fPaint = newPaint;
2522 } else {
2523 fPaint = &paint;
2524 }
2525 }
2526
reed@google.comf67e4cf2011-03-15 20:56:58 +00002527 const SkPaint& paint() const { return *fPaint; }
2528
2529private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002530 const SkPaint* fPaint;
2531 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002532};
2533
reed@google.come0d9ce82014-04-23 04:00:17 +00002534void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2535 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002536 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002537
2538 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002539 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002540 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002541 }
2542
reed@google.com4e2b3d32011-04-07 14:18:59 +00002543 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002544}
2545
reed@google.come0d9ce82014-04-23 04:00:17 +00002546void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2547 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002548 SkPoint textOffset = SkPoint::Make(0, 0);
2549
halcanary96fcdcc2015-08-27 07:41:13 -07002550 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002551
reed@android.com8a1c16f2008-12-17 15:59:43 +00002552 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002553 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002554 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002555 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002556 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002557
reed@google.com4e2b3d32011-04-07 14:18:59 +00002558 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002559}
2560
reed@google.come0d9ce82014-04-23 04:00:17 +00002561void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2562 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002563
2564 SkPoint textOffset = SkPoint::Make(0, constY);
2565
halcanary96fcdcc2015-08-27 07:41:13 -07002566 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002567
reed@android.com8a1c16f2008-12-17 15:59:43 +00002568 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002569 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002570 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002571 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002572 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002573
reed@google.com4e2b3d32011-04-07 14:18:59 +00002574 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002575}
2576
reed@google.come0d9ce82014-04-23 04:00:17 +00002577void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2578 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002579 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002580
reed@android.com8a1c16f2008-12-17 15:59:43 +00002581 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002582 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002583 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002584 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002585
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002586 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002587}
2588
reed45561a02016-07-07 12:47:17 -07002589void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2590 const SkRect* cullRect, const SkPaint& paint) {
2591 if (cullRect && this->quickReject(*cullRect)) {
2592 return;
2593 }
2594
2595 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2596
2597 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002598 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002599 }
2600
2601 LOOPER_END
2602}
2603
fmalita00d5c2c2014-08-21 08:53:26 -07002604void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2605 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002606
fmalita85d5eb92015-03-04 11:20:12 -08002607 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002608 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002609 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002610 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002611 SkRect tmp;
2612 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2613 return;
2614 }
2615 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002616 }
2617
fmalita024f9962015-03-03 19:08:17 -08002618 // We cannot filter in the looper as we normally do, because the paint is
2619 // incomplete at this point (text-related attributes are embedded within blob run paints).
2620 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002621 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002622
fmalita85d5eb92015-03-04 11:20:12 -08002623 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002624
fmalitaaa1b9122014-08-28 14:32:24 -07002625 while (iter.next()) {
2626 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002627 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002628 }
2629
fmalitaaa1b9122014-08-28 14:32:24 -07002630 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002631
2632 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002633}
2634
reed@google.come0d9ce82014-04-23 04:00:17 +00002635// These will become non-virtual, so they always call the (virtual) onDraw... method
2636void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2637 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002638 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002639 if (byteLength) {
2640 this->onDrawText(text, byteLength, x, y, paint);
2641 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002642}
2643void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2644 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002645 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002646 if (byteLength) {
2647 this->onDrawPosText(text, byteLength, pos, paint);
2648 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002649}
2650void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2651 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002652 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002653 if (byteLength) {
2654 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2655 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002656}
2657void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2658 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002659 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002660 if (byteLength) {
2661 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2662 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002663}
reed45561a02016-07-07 12:47:17 -07002664void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2665 const SkRect* cullRect, const SkPaint& paint) {
2666 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2667 if (byteLength) {
2668 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2669 }
2670}
fmalita00d5c2c2014-08-21 08:53:26 -07002671void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2672 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002673 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002674 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002675 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002676}
reed@google.come0d9ce82014-04-23 04:00:17 +00002677
Mike Reede88a1cb2017-03-17 09:50:46 -04002678void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2679 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002680 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2681 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2682
2683 while (iter.next()) {
2684 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002685 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002686 }
2687
2688 LOOPER_END
2689}
2690
dandovb3c9d1c2014-08-12 08:34:29 -07002691void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002692 const SkPoint texCoords[4], SkBlendMode bmode,
2693 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002694 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002695 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002696 return;
2697 }
mtklein6cfa73a2014-08-13 13:33:49 -07002698
Mike Reedfaba3712016-11-03 14:45:31 -04002699 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002700}
2701
2702void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002703 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002704 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002705 // Since a patch is always within the convex hull of the control points, we discard it when its
2706 // bounding rectangle is completely outside the current clip.
2707 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002708 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002709 if (this->quickReject(bounds)) {
2710 return;
2711 }
mtklein6cfa73a2014-08-13 13:33:49 -07002712
halcanary96fcdcc2015-08-27 07:41:13 -07002713 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002714
dandovecfff212014-08-04 10:02:00 -07002715 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002716 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002717 }
mtklein6cfa73a2014-08-13 13:33:49 -07002718
dandovecfff212014-08-04 10:02:00 -07002719 LOOPER_END
2720}
2721
reeda8db7282015-07-07 10:22:31 -07002722void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002723 RETURN_ON_NULL(dr);
2724 if (x || y) {
2725 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2726 this->onDrawDrawable(dr, &matrix);
2727 } else {
2728 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002729 }
2730}
2731
reeda8db7282015-07-07 10:22:31 -07002732void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002733 RETURN_ON_NULL(dr);
2734 if (matrix && matrix->isIdentity()) {
2735 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002736 }
reede3b38ce2016-01-08 09:18:44 -08002737 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002738}
2739
2740void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002741 // drawable bounds are no longer reliable (e.g. android displaylist)
2742 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002743 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002744}
2745
reed71c3c762015-06-24 10:29:17 -07002746void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002747 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002748 const SkRect* cull, const SkPaint* paint) {
2749 if (cull && this->quickReject(*cull)) {
2750 return;
2751 }
2752
2753 SkPaint pnt;
2754 if (paint) {
2755 pnt = *paint;
2756 }
halcanary9d524f22016-03-29 09:03:52 -07002757
halcanary96fcdcc2015-08-27 07:41:13 -07002758 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002759 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002760 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002761 }
2762 LOOPER_END
2763}
2764
reedf70b5312016-03-04 16:36:20 -08002765void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2766 SkASSERT(key);
2767
2768 SkPaint paint;
2769 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2770 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002771 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002772 }
2773 LOOPER_END
2774}
2775
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776//////////////////////////////////////////////////////////////////////////////
2777// These methods are NOT virtual, and therefore must call back into virtual
2778// methods, rather than actually drawing themselves.
2779//////////////////////////////////////////////////////////////////////////////
2780
reed374772b2016-10-05 17:33:02 -07002781void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002782 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783 SkPaint paint;
2784
2785 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002786 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002787 this->drawPaint(paint);
2788}
2789
2790void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002791 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002792 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002793 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2794}
2795
Mike Reed3661bc92017-02-22 13:21:42 -05002796void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002797 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002799
reed@android.com8a1c16f2008-12-17 15:59:43 +00002800 pts[0].set(x0, y0);
2801 pts[1].set(x1, y1);
2802 this->drawPoints(kLines_PointMode, 2, pts, paint);
2803}
2804
Mike Reed3661bc92017-02-22 13:21:42 -05002805void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002806 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807 if (radius < 0) {
2808 radius = 0;
2809 }
2810
2811 SkRect r;
2812 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002813 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814}
2815
2816void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2817 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002818 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002819 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002820 SkRRect rrect;
2821 rrect.setRectXY(r, rx, ry);
2822 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823 } else {
2824 this->drawRect(r, paint);
2825 }
2826}
2827
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2829 SkScalar sweepAngle, bool useCenter,
2830 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002831 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002832 if (oval.isEmpty() || !sweepAngle) {
2833 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002834 }
bsalomon21af9ca2016-08-25 12:29:23 -07002835 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002836}
2837
2838void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2839 const SkPath& path, SkScalar hOffset,
2840 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002841 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002843
reed@android.com8a1c16f2008-12-17 15:59:43 +00002844 matrix.setTranslate(hOffset, vOffset);
2845 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2846}
2847
reed@android.comf76bacf2009-05-13 14:00:33 +00002848///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002849
2850/**
2851 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2852 * against the playback cost of recursing into the subpicture to get at its actual ops.
2853 *
2854 * For now we pick a conservatively small value, though measurement (and other heuristics like
2855 * the type of ops contained) may justify changing this value.
2856 */
2857#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002858
reedd5fa1a42014-08-09 11:08:05 -07002859void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002860 RETURN_ON_NULL(picture);
2861
reed1c2c4412015-04-30 13:09:24 -07002862 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002863 if (matrix && matrix->isIdentity()) {
2864 matrix = nullptr;
2865 }
2866 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2867 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2868 picture->playback(this);
2869 } else {
2870 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002871 }
2872}
robertphillips9b14f262014-06-04 05:40:44 -07002873
reedd5fa1a42014-08-09 11:08:05 -07002874void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2875 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002876 if (!paint || paint->canComputeFastBounds()) {
2877 SkRect bounds = picture->cullRect();
2878 if (paint) {
2879 paint->computeFastBounds(bounds, &bounds);
2880 }
2881 if (matrix) {
2882 matrix->mapRect(&bounds);
2883 }
2884 if (this->quickReject(bounds)) {
2885 return;
2886 }
2887 }
2888
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002889 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002890 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002891}
2892
vjiaoblack95302da2016-07-21 10:25:54 -07002893#ifdef SK_EXPERIMENTAL_SHADOWING
2894void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2895 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002896 const SkPaint* paint,
2897 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002898 RETURN_ON_NULL(picture);
2899
2900 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2901
vjiaoblacke6f5d562016-08-25 06:30:23 -07002902 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002903}
2904
2905void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2906 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002907 const SkPaint* paint,
2908 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002909 if (!paint || paint->canComputeFastBounds()) {
2910 SkRect bounds = picture->cullRect();
2911 if (paint) {
2912 paint->computeFastBounds(bounds, &bounds);
2913 }
2914 if (matrix) {
2915 matrix->mapRect(&bounds);
2916 }
2917 if (this->quickReject(bounds)) {
2918 return;
2919 }
2920 }
2921
2922 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2923
vjiaoblacke6f5d562016-08-25 06:30:23 -07002924 sk_sp<SkImage> povDepthMap;
2925 sk_sp<SkImage> diffuseMap;
2926
vjiaoblack904527d2016-08-09 09:32:09 -07002927 // povDepthMap
2928 {
2929 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002930 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2931 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002932 sk_sp<SkLights> povLight = builder.finish();
2933
2934 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2935 picture->cullRect().height(),
2936 kBGRA_8888_SkColorType,
2937 kOpaque_SkAlphaType);
2938
2939 // Create a new surface (that matches the backend of canvas)
2940 // to create the povDepthMap
2941 sk_sp<SkSurface> surf(this->makeSurface(info));
2942
2943 // Wrap another SPFCanvas around the surface
2944 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2945 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2946
2947 // set the depth map canvas to have the light as the user's POV
2948 depthMapCanvas->setLights(std::move(povLight));
2949
2950 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002951 povDepthMap = surf->makeImageSnapshot();
2952 }
2953
2954 // diffuseMap
2955 {
2956 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2957 picture->cullRect().height(),
2958 kBGRA_8888_SkColorType,
2959 kOpaque_SkAlphaType);
2960
2961 sk_sp<SkSurface> surf(this->makeSurface(info));
2962 surf->getCanvas()->drawPicture(picture);
2963
2964 diffuseMap = surf->makeImageSnapshot();
2965 }
vjiaoblack904527d2016-08-09 09:32:09 -07002966
2967 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
2968 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07002969 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
2970 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07002971
2972 // TODO: pass the depth to the shader in vertices, or uniforms
2973 // so we don't have to render depth and color separately
2974 for (int i = 0; i < fLights->numLights(); ++i) {
2975 // skip over ambient lights; they don't cast shadows
2976 // lights that have shadow maps do not need updating (because lights are immutable)
2977 sk_sp<SkImage> depthMap;
2978 SkISize shMapSize;
2979
2980 if (fLights->light(i).getShadowMap() != nullptr) {
2981 continue;
2982 }
2983
2984 if (fLights->light(i).isRadial()) {
2985 shMapSize.fHeight = 1;
2986 shMapSize.fWidth = (int) picture->cullRect().width();
2987
2988 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
2989 kBGRA_8888_SkColorType,
2990 kOpaque_SkAlphaType);
2991
2992 // Create new surface (that matches the backend of canvas)
2993 // for each shadow map
2994 sk_sp<SkSurface> surf(this->makeSurface(info));
2995
2996 // Wrap another SPFCanvas around the surface
2997 SkCanvas* depthMapCanvas = surf->getCanvas();
2998
2999 SkLights::Builder builder;
3000 builder.add(fLights->light(i));
3001 sk_sp<SkLights> curLight = builder.finish();
3002
3003 sk_sp<SkShader> shadowMapShader;
3004 shadowMapShader = SkRadialShadowMapShader::Make(
3005 povDepthShader, curLight,
3006 (int) picture->cullRect().width(),
3007 (int) picture->cullRect().height());
3008
3009 SkPaint shadowMapPaint;
3010 shadowMapPaint.setShader(std::move(shadowMapShader));
3011
3012 depthMapCanvas->setLights(curLight);
3013
3014 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3015 diffuseMap->height()),
3016 shadowMapPaint);
3017
3018 depthMap = surf->makeImageSnapshot();
3019
3020 } else {
3021 // TODO: compute the correct size of the depth map from the light properties
3022 // TODO: maybe add a kDepth_8_SkColorType
3023 // TODO: find actual max depth of picture
3024 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3025 fLights->light(i), 255,
3026 (int) picture->cullRect().width(),
3027 (int) picture->cullRect().height());
3028
3029 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3030 kBGRA_8888_SkColorType,
3031 kOpaque_SkAlphaType);
3032
3033 // Create a new surface (that matches the backend of canvas)
3034 // for each shadow map
3035 sk_sp<SkSurface> surf(this->makeSurface(info));
3036
3037 // Wrap another SPFCanvas around the surface
3038 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3039 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3040 depthMapCanvas->setShadowParams(params);
3041
3042 // set the depth map canvas to have the light we're drawing.
3043 SkLights::Builder builder;
3044 builder.add(fLights->light(i));
3045 sk_sp<SkLights> curLight = builder.finish();
3046 depthMapCanvas->setLights(std::move(curLight));
3047
3048 depthMapCanvas->drawPicture(picture);
3049 depthMap = surf->makeImageSnapshot();
3050 }
3051
3052 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3053 fLights->light(i).setShadowMap(std::move(depthMap));
3054 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3055 // we blur the variance map
3056 SkPaint blurPaint;
3057 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3058 params.fShadowRadius, nullptr));
3059
3060 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3061 kBGRA_8888_SkColorType,
3062 kOpaque_SkAlphaType);
3063
3064 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3065
3066 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3067
3068 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3069 }
3070 }
3071
3072 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003073 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3074 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003075 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003076 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003077 diffuseMap->height(),
3078 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003079
3080 shadowPaint.setShader(shadowShader);
3081
3082 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003083}
3084#endif
3085
reed@android.com8a1c16f2008-12-17 15:59:43 +00003086///////////////////////////////////////////////////////////////////////////////
3087///////////////////////////////////////////////////////////////////////////////
3088
reed3aafe112016-08-18 12:45:34 -07003089SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003090 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003091
3092 SkASSERT(canvas);
3093
reed3aafe112016-08-18 12:45:34 -07003094 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003095 fDone = !fImpl->next();
3096}
3097
3098SkCanvas::LayerIter::~LayerIter() {
3099 fImpl->~SkDrawIter();
3100}
3101
3102void SkCanvas::LayerIter::next() {
3103 fDone = !fImpl->next();
3104}
3105
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003106SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003107 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003108}
3109
3110const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003111 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003112}
3113
3114const SkPaint& SkCanvas::LayerIter::paint() const {
3115 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003116 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003117 paint = &fDefaultPaint;
3118 }
3119 return *paint;
3120}
3121
Mike Reeda1361362017-03-07 09:37:29 -05003122void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3123 return fImpl->fDevice->onAsRgnClip(rgn);
3124}
3125
reed@android.com8a1c16f2008-12-17 15:59:43 +00003126int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3127int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003128
3129///////////////////////////////////////////////////////////////////////////////
3130
Mike Reed93b1b4f2017-04-05 16:21:47 -04003131#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP
Mike Reed8310f0e2017-03-08 21:42:37 +00003132SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
Mike Reed93b1b4f2017-04-05 16:21:47 -04003133#endif
Mike Reed8310f0e2017-03-08 21:42:37 +00003134
3135///////////////////////////////////////////////////////////////////////////////
3136
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003137static bool supported_for_raster_canvas(const SkImageInfo& info) {
3138 switch (info.alphaType()) {
3139 case kPremul_SkAlphaType:
3140 case kOpaque_SkAlphaType:
3141 break;
3142 default:
3143 return false;
3144 }
3145
3146 switch (info.colorType()) {
3147 case kAlpha_8_SkColorType:
3148 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003149 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003150 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003151 break;
3152 default:
3153 return false;
3154 }
3155
3156 return true;
3157}
3158
Mike Reed5df49342016-11-12 08:06:55 -06003159std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3160 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003161 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003162 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003163 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003164
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003165 SkBitmap bitmap;
3166 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003167 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003168 }
Mike Reed5df49342016-11-12 08:06:55 -06003169 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003170}
reedd5fa1a42014-08-09 11:08:05 -07003171
3172///////////////////////////////////////////////////////////////////////////////
3173
3174SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003175 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003176 : fCanvas(canvas)
3177 , fSaveCount(canvas->getSaveCount())
3178{
bsalomon49f085d2014-09-05 13:34:00 -07003179 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003180 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003181 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003182 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003183 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003184 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003185 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003186 canvas->save();
3187 }
mtklein6cfa73a2014-08-13 13:33:49 -07003188
bsalomon49f085d2014-09-05 13:34:00 -07003189 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003190 canvas->concat(*matrix);
3191 }
3192}
3193
3194SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3195 fCanvas->restoreToCount(fSaveCount);
3196}
reede8f30622016-03-23 18:59:25 -07003197
Florin Malitaee424ac2016-12-01 12:47:59 -05003198///////////////////////////////////////////////////////////////////////////////
3199
3200SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3201 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3202
Florin Malita439ace92016-12-02 12:05:41 -05003203SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3204 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3205
Florin Malitaee424ac2016-12-01 12:47:59 -05003206SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3207 (void)this->INHERITED::getSaveLayerStrategy(rec);
3208 return kNoLayer_SaveLayerStrategy;
3209}
3210
3211///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003212
reed73603f32016-09-20 08:42:38 -07003213static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3214static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3215static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3216static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3217static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3218static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003219
3220///////////////////////////////////////////////////////////////////////////////////////////////////
3221
3222SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3223 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3224 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3225 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3226 SkIPoint origin = dev->getOrigin();
3227 SkMatrix ctm = this->getTotalMatrix();
3228 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3229
3230 SkIRect clip = fMCRec->fRasterClip.getBounds();
3231 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003232 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003233 clip.setEmpty();
3234 }
3235
3236 fAllocator->updateHandle(handle, ctm, clip);
3237 return handle;
3238 }
3239 return nullptr;
3240}
3241
3242static bool install(SkBitmap* bm, const SkImageInfo& info,
3243 const SkRasterHandleAllocator::Rec& rec) {
3244 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3245 rec.fReleaseProc, rec.fReleaseCtx);
3246}
3247
3248SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3249 SkBitmap* bm) {
3250 SkRasterHandleAllocator::Rec rec;
3251 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3252 return nullptr;
3253 }
3254 return rec.fHandle;
3255}
3256
3257std::unique_ptr<SkCanvas>
3258SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3259 const SkImageInfo& info, const Rec* rec) {
3260 if (!alloc || !supported_for_raster_canvas(info)) {
3261 return nullptr;
3262 }
3263
3264 SkBitmap bm;
3265 Handle hndl;
3266
3267 if (rec) {
3268 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3269 } else {
3270 hndl = alloc->allocBitmap(info, &bm);
3271 }
3272 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3273}