blob: aa69f09f47d41ec5e6d61ab4bffb9b1dea6a8bb6 [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
1773 // be able to assert...
1774 // SkASSERT(outer.contains(inner));
1775 //
1776 // For now at least check for containment of bounds
1777 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1778
1779 this->onDrawDRRect(outer, inner, paint);
1780}
1781
reed41af9662015-01-05 07:49:08 -08001782// These need to stop being virtual -- clients need to override the onDraw... versions
1783
1784void SkCanvas::drawPaint(const SkPaint& paint) {
1785 this->onDrawPaint(paint);
1786}
1787
1788void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1789 this->onDrawRect(r, paint);
1790}
1791
msarettdca352e2016-08-26 06:37:45 -07001792void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1793 if (region.isEmpty()) {
1794 return;
1795 }
1796
1797 if (region.isRect()) {
1798 return this->drawIRect(region.getBounds(), paint);
1799 }
1800
1801 this->onDrawRegion(region, paint);
1802}
1803
reed41af9662015-01-05 07:49:08 -08001804void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1805 this->onDrawOval(r, paint);
1806}
1807
1808void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1809 this->onDrawRRect(rrect, paint);
1810}
1811
1812void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1813 this->onDrawPoints(mode, count, pts, paint);
1814}
1815
Mike Reede88a1cb2017-03-17 09:50:46 -04001816void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1817 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001818 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001819 this->onDrawVerticesObject(vertices.get(), mode, paint);
1820}
1821
1822void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1823 RETURN_ON_NULL(vertices);
1824 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001825}
1826
1827void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1828 this->onDrawPath(path, paint);
1829}
1830
reeda85d4d02015-05-06 12:56:48 -07001831void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001832 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001833 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001834}
1835
reede47829b2015-08-06 10:02:53 -07001836void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1837 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001838 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001839 if (dst.isEmpty() || src.isEmpty()) {
1840 return;
1841 }
1842 this->onDrawImageRect(image, &src, dst, paint, constraint);
1843}
reed41af9662015-01-05 07:49:08 -08001844
reed84984ef2015-07-17 07:09:43 -07001845void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1846 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001847 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001848 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001849}
1850
reede47829b2015-08-06 10:02:53 -07001851void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1852 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001853 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001854 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1855 constraint);
1856}
reede47829b2015-08-06 10:02:53 -07001857
reed4c21dc52015-06-25 12:32:03 -07001858void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1859 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001860 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001861 if (dst.isEmpty()) {
1862 return;
1863 }
msarett552bca92016-08-03 06:53:26 -07001864 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1865 this->onDrawImageNine(image, center, dst, paint);
1866 } else {
reede47829b2015-08-06 10:02:53 -07001867 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001868 }
reed4c21dc52015-06-25 12:32:03 -07001869}
1870
msarett16882062016-08-16 09:31:08 -07001871void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1872 const SkPaint* paint) {
1873 RETURN_ON_NULL(image);
1874 if (dst.isEmpty()) {
1875 return;
1876 }
msarett71df2d72016-09-30 12:41:42 -07001877
1878 SkIRect bounds;
1879 Lattice latticePlusBounds = lattice;
1880 if (!latticePlusBounds.fBounds) {
1881 bounds = SkIRect::MakeWH(image->width(), image->height());
1882 latticePlusBounds.fBounds = &bounds;
1883 }
1884
1885 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1886 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001887 } else {
1888 this->drawImageRect(image, dst, paint);
1889 }
1890}
1891
reed41af9662015-01-05 07:49:08 -08001892void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001893 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001894 return;
1895 }
reed41af9662015-01-05 07:49:08 -08001896 this->onDrawBitmap(bitmap, dx, dy, paint);
1897}
1898
reede47829b2015-08-06 10:02:53 -07001899void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001900 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001901 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001902 return;
1903 }
reede47829b2015-08-06 10:02:53 -07001904 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001905}
1906
reed84984ef2015-07-17 07:09:43 -07001907void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1908 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001909 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001910}
1911
reede47829b2015-08-06 10:02:53 -07001912void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1913 SrcRectConstraint constraint) {
1914 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1915 constraint);
1916}
reede47829b2015-08-06 10:02:53 -07001917
reed41af9662015-01-05 07:49:08 -08001918void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1919 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001920 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001921 return;
1922 }
msarett552bca92016-08-03 06:53:26 -07001923 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1924 this->onDrawBitmapNine(bitmap, center, dst, paint);
1925 } else {
reeda5517e22015-07-14 10:54:12 -07001926 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001927 }
reed41af9662015-01-05 07:49:08 -08001928}
1929
msarettc573a402016-08-02 08:05:56 -07001930void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1931 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001932 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001933 return;
1934 }
msarett71df2d72016-09-30 12:41:42 -07001935
1936 SkIRect bounds;
1937 Lattice latticePlusBounds = lattice;
1938 if (!latticePlusBounds.fBounds) {
1939 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1940 latticePlusBounds.fBounds = &bounds;
1941 }
1942
1943 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1944 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001945 } else {
msarett16882062016-08-16 09:31:08 -07001946 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001947 }
msarettc573a402016-08-02 08:05:56 -07001948}
1949
reed71c3c762015-06-24 10:29:17 -07001950void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001951 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001952 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001953 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001954 if (count <= 0) {
1955 return;
1956 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001957 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001958 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001959 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001960}
1961
reedf70b5312016-03-04 16:36:20 -08001962void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1963 if (key) {
1964 this->onDrawAnnotation(rect, key, value);
1965 }
1966}
1967
reede47829b2015-08-06 10:02:53 -07001968void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1969 const SkPaint* paint, SrcRectConstraint constraint) {
1970 if (src) {
1971 this->drawImageRect(image, *src, dst, paint, constraint);
1972 } else {
1973 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1974 dst, paint, constraint);
1975 }
1976}
1977void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1978 const SkPaint* paint, SrcRectConstraint constraint) {
1979 if (src) {
1980 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1981 } else {
1982 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1983 dst, paint, constraint);
1984 }
1985}
1986
tomhudsoncb3bd182016-05-18 07:24:16 -07001987void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1988 SkIRect layer_bounds = this->getTopLayerBounds();
1989 if (matrix) {
1990 *matrix = this->getTotalMatrix();
1991 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1992 }
1993 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001994 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001995 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1996 }
1997}
1998
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999//////////////////////////////////////////////////////////////////////////////
2000// These are the virtual drawing methods
2001//////////////////////////////////////////////////////////////////////////////
2002
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002003void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002004 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002005 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2006 }
2007}
2008
reed41af9662015-01-05 07:49:08 -08002009void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002010 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002011 this->internalDrawPaint(paint);
2012}
2013
2014void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002015 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002016
2017 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002018 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002019 }
2020
reed@google.com4e2b3d32011-04-07 14:18:59 +00002021 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002022}
2023
reed41af9662015-01-05 07:49:08 -08002024void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2025 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002026 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002027 if ((long)count <= 0) {
2028 return;
2029 }
2030
Mike Reed822128b2017-02-28 16:41:03 -05002031 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002032 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002033 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002034 // special-case 2 points (common for drawing a single line)
2035 if (2 == count) {
2036 r.set(pts[0], pts[1]);
2037 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002038 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002039 }
Mike Reed822128b2017-02-28 16:41:03 -05002040 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002041 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2042 return;
2043 }
2044 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002045 }
reed@google.coma584aed2012-05-16 14:06:02 +00002046
halcanary96fcdcc2015-08-27 07:41:13 -07002047 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002048
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002049 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002050
reed@android.com8a1c16f2008-12-17 15:59:43 +00002051 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002052 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002053 }
reed@google.com4b226022011-01-11 18:32:13 +00002054
reed@google.com4e2b3d32011-04-07 14:18:59 +00002055 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002056}
2057
reed4a167172016-08-18 17:15:25 -07002058static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2059 return ((intptr_t)paint.getImageFilter() |
2060#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2061 (intptr_t)canvas->getDrawFilter() |
2062#endif
2063 (intptr_t)paint.getLooper() ) != 0;
2064}
2065
reed41af9662015-01-05 07:49:08 -08002066void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002067 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002068 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002069 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2070 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2071 SkRect tmp(r);
2072 tmp.sort();
2073
Mike Reed822128b2017-02-28 16:41:03 -05002074 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002075 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2076 return;
2077 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002078 }
reed@google.com4b226022011-01-11 18:32:13 +00002079
reed4a167172016-08-18 17:15:25 -07002080 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002081 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082
reed4a167172016-08-18 17:15:25 -07002083 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002084 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002085 }
2086
2087 LOOPER_END
2088 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002089 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002090 SkDrawIter iter(this);
2091 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002092 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002093 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002094 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002095}
2096
msarett44df6512016-08-25 13:54:30 -07002097void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002098 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002099 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002100 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002101 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2102 return;
2103 }
msarett44df6512016-08-25 13:54:30 -07002104 }
2105
Mike Reed822128b2017-02-28 16:41:03 -05002106 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002107
2108 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002109 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002110 }
2111
2112 LOOPER_END
2113}
2114
reed41af9662015-01-05 07:49:08 -08002115void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002116 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002117 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002118 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002119 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2120 return;
2121 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002122 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002123
Mike Reed822128b2017-02-28 16:41:03 -05002124 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002125
2126 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002127 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002128 }
2129
2130 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002131}
2132
bsalomonac3aa242016-08-19 11:25:19 -07002133void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2134 SkScalar sweepAngle, bool useCenter,
2135 const SkPaint& paint) {
2136 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002137 if (paint.canComputeFastBounds()) {
2138 SkRect storage;
2139 // Note we're using the entire oval as the bounds.
2140 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2141 return;
2142 }
bsalomonac3aa242016-08-19 11:25:19 -07002143 }
2144
Mike Reed822128b2017-02-28 16:41:03 -05002145 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002146
2147 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002148 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002149 }
2150
2151 LOOPER_END
2152}
2153
reed41af9662015-01-05 07:49:08 -08002154void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002155 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002156 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002157 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002158 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2159 return;
2160 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002161 }
2162
2163 if (rrect.isRect()) {
2164 // call the non-virtual version
2165 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002166 return;
2167 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002168 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002169 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2170 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002171 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002172
Mike Reed822128b2017-02-28 16:41:03 -05002173 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002174
2175 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002176 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002177 }
2178
2179 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002180}
2181
Mike Reed822128b2017-02-28 16:41:03 -05002182void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002183 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002184 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002185 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2186 return;
2187 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002188 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002189
Mike Reed822128b2017-02-28 16:41:03 -05002190 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002191
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002192 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002193 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002194 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002195
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002196 LOOPER_END
2197}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002198
reed41af9662015-01-05 07:49:08 -08002199void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002200 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002201 if (!path.isFinite()) {
2202 return;
2203 }
2204
Mike Reed822128b2017-02-28 16:41:03 -05002205 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002206 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002207 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002208 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2209 return;
2210 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002211 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002212
Mike Reed822128b2017-02-28 16:41:03 -05002213 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002214 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002215 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002216 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002217 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002218 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002219
Mike Reed822128b2017-02-28 16:41:03 -05002220 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002221
2222 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002223 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002224 }
2225
reed@google.com4e2b3d32011-04-07 14:18:59 +00002226 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002227}
2228
reed262a71b2015-12-05 13:07:27 -08002229bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002230 if (!paint.getImageFilter()) {
2231 return false;
2232 }
2233
2234 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002235 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002236 return false;
2237 }
2238
2239 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2240 // Once we can filter and the filter will return a result larger than itself, we should be
2241 // able to remove this constraint.
2242 // skbug.com/4526
2243 //
2244 SkPoint pt;
2245 ctm.mapXY(x, y, &pt);
2246 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2247 return ir.contains(fMCRec->fRasterClip.getBounds());
2248}
2249
reeda85d4d02015-05-06 12:56:48 -07002250void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002251 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002252 SkRect bounds = SkRect::MakeXYWH(x, y,
2253 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002254 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002255 SkRect tmp = bounds;
2256 if (paint) {
2257 paint->computeFastBounds(tmp, &tmp);
2258 }
2259 if (this->quickReject(tmp)) {
2260 return;
2261 }
reeda85d4d02015-05-06 12:56:48 -07002262 }
halcanary9d524f22016-03-29 09:03:52 -07002263
reeda85d4d02015-05-06 12:56:48 -07002264 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002265 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002266 paint = lazy.init();
2267 }
reed262a71b2015-12-05 13:07:27 -08002268
reeda2217ef2016-07-20 06:04:34 -07002269 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002270 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2271 *paint);
2272 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002273 special = this->getDevice()->makeSpecial(image);
2274 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002275 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002276 }
2277 }
2278
reed262a71b2015-12-05 13:07:27 -08002279 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2280
reeda85d4d02015-05-06 12:56:48 -07002281 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002282 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002283 if (special) {
2284 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002285 iter.fDevice->ctm().mapXY(x, y, &pt);
2286 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002287 SkScalarRoundToInt(pt.fX),
2288 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002289 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002290 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002291 }
reeda85d4d02015-05-06 12:56:48 -07002292 }
halcanary9d524f22016-03-29 09:03:52 -07002293
reeda85d4d02015-05-06 12:56:48 -07002294 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002295}
2296
reed41af9662015-01-05 07:49:08 -08002297void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002298 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002299 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002300 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002301 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002302 if (paint) {
2303 paint->computeFastBounds(dst, &storage);
2304 }
2305 if (this->quickReject(storage)) {
2306 return;
2307 }
reeda85d4d02015-05-06 12:56:48 -07002308 }
2309 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002310 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002311 paint = lazy.init();
2312 }
halcanary9d524f22016-03-29 09:03:52 -07002313
senorblancoc41e7e12015-12-07 12:51:30 -08002314 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002315 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002316
reeda85d4d02015-05-06 12:56:48 -07002317 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002318 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002319 }
halcanary9d524f22016-03-29 09:03:52 -07002320
reeda85d4d02015-05-06 12:56:48 -07002321 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002322}
2323
reed41af9662015-01-05 07:49:08 -08002324void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002325 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002326 SkDEBUGCODE(bitmap.validate();)
2327
reed33366972015-10-08 09:22:02 -07002328 if (bitmap.drawsNothing()) {
2329 return;
2330 }
2331
2332 SkLazyPaint lazy;
2333 if (nullptr == paint) {
2334 paint = lazy.init();
2335 }
2336
Mike Reed822128b2017-02-28 16:41:03 -05002337 SkRect bounds;
2338 bitmap.getBounds(&bounds);
2339 bounds.offset(x, y);
2340 bool canFastBounds = paint->canComputeFastBounds();
2341 if (canFastBounds) {
2342 SkRect storage;
2343 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002344 return;
2345 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002346 }
reed@google.com4b226022011-01-11 18:32:13 +00002347
reeda2217ef2016-07-20 06:04:34 -07002348 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002349 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2350 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002351 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002352 special = this->getDevice()->makeSpecial(bitmap);
2353 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002354 drawAsSprite = false;
2355 }
2356 }
2357
Mike Reed822128b2017-02-28 16:41:03 -05002358 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2359
2360 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002361
2362 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002363 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002364 if (special) {
reed262a71b2015-12-05 13:07:27 -08002365 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002366 iter.fDevice->ctm().mapXY(x, y, &pt);
2367 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002368 SkScalarRoundToInt(pt.fX),
2369 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002370 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002371 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002372 }
reed33366972015-10-08 09:22:02 -07002373 }
msarettfbfa2582016-08-12 08:29:08 -07002374
reed33366972015-10-08 09:22:02 -07002375 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002376}
2377
reed@google.com9987ec32011-09-07 11:57:52 +00002378// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002379void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002380 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002381 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002382 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002383 return;
2384 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002385
halcanary96fcdcc2015-08-27 07:41:13 -07002386 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002387 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002388 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2389 return;
2390 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002391 }
reed@google.com3d608122011-11-21 15:16:16 +00002392
reed@google.com33535f32012-09-25 15:37:50 +00002393 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002394 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002395 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002396 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002397
senorblancoc41e7e12015-12-07 12:51:30 -08002398 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002399 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002400
reed@google.com33535f32012-09-25 15:37:50 +00002401 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002402 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002403 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002404
reed@google.com33535f32012-09-25 15:37:50 +00002405 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002406}
2407
reed41af9662015-01-05 07:49:08 -08002408void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002409 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002410 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002411 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002412 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002413}
2414
reed4c21dc52015-06-25 12:32:03 -07002415void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2416 const SkPaint* paint) {
2417 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002418
halcanary96fcdcc2015-08-27 07:41:13 -07002419 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002420 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002421 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2422 return;
2423 }
reed@google.com3d608122011-11-21 15:16:16 +00002424 }
halcanary9d524f22016-03-29 09:03:52 -07002425
reed4c21dc52015-06-25 12:32:03 -07002426 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002427 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002428 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002429 }
halcanary9d524f22016-03-29 09:03:52 -07002430
senorblancoc41e7e12015-12-07 12:51:30 -08002431 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002432
reed4c21dc52015-06-25 12:32:03 -07002433 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002434 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002435 }
halcanary9d524f22016-03-29 09:03:52 -07002436
reed4c21dc52015-06-25 12:32:03 -07002437 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002438}
2439
reed41af9662015-01-05 07:49:08 -08002440void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2441 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002442 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002443 SkDEBUGCODE(bitmap.validate();)
2444
halcanary96fcdcc2015-08-27 07:41:13 -07002445 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002446 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002447 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2448 return;
2449 }
reed4c21dc52015-06-25 12:32:03 -07002450 }
halcanary9d524f22016-03-29 09:03:52 -07002451
reed4c21dc52015-06-25 12:32:03 -07002452 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002453 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002454 paint = lazy.init();
2455 }
halcanary9d524f22016-03-29 09:03:52 -07002456
senorblancoc41e7e12015-12-07 12:51:30 -08002457 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002458
reed4c21dc52015-06-25 12:32:03 -07002459 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002460 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002461 }
halcanary9d524f22016-03-29 09:03:52 -07002462
reed4c21dc52015-06-25 12:32:03 -07002463 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002464}
2465
msarett16882062016-08-16 09:31:08 -07002466void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2467 const SkPaint* paint) {
2468 if (nullptr == paint || paint->canComputeFastBounds()) {
2469 SkRect storage;
2470 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2471 return;
2472 }
2473 }
2474
2475 SkLazyPaint lazy;
2476 if (nullptr == paint) {
2477 paint = lazy.init();
2478 }
2479
2480 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2481
2482 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002483 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002484 }
2485
2486 LOOPER_END
2487}
2488
2489void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2490 const SkRect& dst, const SkPaint* paint) {
2491 if (nullptr == paint || paint->canComputeFastBounds()) {
2492 SkRect storage;
2493 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2494 return;
2495 }
2496 }
2497
2498 SkLazyPaint lazy;
2499 if (nullptr == paint) {
2500 paint = lazy.init();
2501 }
2502
2503 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2504
2505 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002506 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002507 }
2508
2509 LOOPER_END
2510}
2511
reed@google.comf67e4cf2011-03-15 20:56:58 +00002512class SkDeviceFilteredPaint {
2513public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002514 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002515 uint32_t filteredFlags = device->filterTextFlags(paint);
2516 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002517 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002518 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002519 fPaint = newPaint;
2520 } else {
2521 fPaint = &paint;
2522 }
2523 }
2524
reed@google.comf67e4cf2011-03-15 20:56:58 +00002525 const SkPaint& paint() const { return *fPaint; }
2526
2527private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002528 const SkPaint* fPaint;
2529 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002530};
2531
reed@google.come0d9ce82014-04-23 04:00:17 +00002532void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2533 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002534 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002535
2536 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002537 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002538 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002539 }
2540
reed@google.com4e2b3d32011-04-07 14:18:59 +00002541 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002542}
2543
reed@google.come0d9ce82014-04-23 04:00:17 +00002544void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2545 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002546 SkPoint textOffset = SkPoint::Make(0, 0);
2547
halcanary96fcdcc2015-08-27 07:41:13 -07002548 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002549
reed@android.com8a1c16f2008-12-17 15:59:43 +00002550 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002551 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002552 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002553 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002554 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002555
reed@google.com4e2b3d32011-04-07 14:18:59 +00002556 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002557}
2558
reed@google.come0d9ce82014-04-23 04:00:17 +00002559void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2560 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002561
2562 SkPoint textOffset = SkPoint::Make(0, constY);
2563
halcanary96fcdcc2015-08-27 07:41:13 -07002564 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002565
reed@android.com8a1c16f2008-12-17 15:59:43 +00002566 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002567 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002568 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002569 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002570 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002571
reed@google.com4e2b3d32011-04-07 14:18:59 +00002572 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002573}
2574
reed@google.come0d9ce82014-04-23 04:00:17 +00002575void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2576 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002577 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002578
reed@android.com8a1c16f2008-12-17 15:59:43 +00002579 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002580 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002581 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002582 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002583
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002584 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002585}
2586
reed45561a02016-07-07 12:47:17 -07002587void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2588 const SkRect* cullRect, const SkPaint& paint) {
2589 if (cullRect && this->quickReject(*cullRect)) {
2590 return;
2591 }
2592
2593 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2594
2595 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002596 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002597 }
2598
2599 LOOPER_END
2600}
2601
fmalita00d5c2c2014-08-21 08:53:26 -07002602void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2603 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002604
fmalita85d5eb92015-03-04 11:20:12 -08002605 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002606 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002607 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002608 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002609 SkRect tmp;
2610 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2611 return;
2612 }
2613 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002614 }
2615
fmalita024f9962015-03-03 19:08:17 -08002616 // We cannot filter in the looper as we normally do, because the paint is
2617 // incomplete at this point (text-related attributes are embedded within blob run paints).
2618 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002619 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002620
fmalita85d5eb92015-03-04 11:20:12 -08002621 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002622
fmalitaaa1b9122014-08-28 14:32:24 -07002623 while (iter.next()) {
2624 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002625 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002626 }
2627
fmalitaaa1b9122014-08-28 14:32:24 -07002628 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002629
2630 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002631}
2632
reed@google.come0d9ce82014-04-23 04:00:17 +00002633// These will become non-virtual, so they always call the (virtual) onDraw... method
2634void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2635 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002636 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002637 if (byteLength) {
2638 this->onDrawText(text, byteLength, x, y, paint);
2639 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002640}
2641void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2642 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002643 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002644 if (byteLength) {
2645 this->onDrawPosText(text, byteLength, pos, paint);
2646 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002647}
2648void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2649 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002650 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002651 if (byteLength) {
2652 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2653 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002654}
2655void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2656 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002657 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002658 if (byteLength) {
2659 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2660 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002661}
reed45561a02016-07-07 12:47:17 -07002662void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2663 const SkRect* cullRect, const SkPaint& paint) {
2664 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2665 if (byteLength) {
2666 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2667 }
2668}
fmalita00d5c2c2014-08-21 08:53:26 -07002669void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2670 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002671 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002672 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002673 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002674}
reed@google.come0d9ce82014-04-23 04:00:17 +00002675
Mike Reede88a1cb2017-03-17 09:50:46 -04002676void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2677 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002678 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2679 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2680
2681 while (iter.next()) {
2682 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002683 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002684 }
2685
2686 LOOPER_END
2687}
2688
dandovb3c9d1c2014-08-12 08:34:29 -07002689void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002690 const SkPoint texCoords[4], SkBlendMode bmode,
2691 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002692 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002693 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002694 return;
2695 }
mtklein6cfa73a2014-08-13 13:33:49 -07002696
Mike Reedfaba3712016-11-03 14:45:31 -04002697 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002698}
2699
2700void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002701 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002702 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002703 // Since a patch is always within the convex hull of the control points, we discard it when its
2704 // bounding rectangle is completely outside the current clip.
2705 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002706 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002707 if (this->quickReject(bounds)) {
2708 return;
2709 }
mtklein6cfa73a2014-08-13 13:33:49 -07002710
halcanary96fcdcc2015-08-27 07:41:13 -07002711 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002712
dandovecfff212014-08-04 10:02:00 -07002713 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002714 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002715 }
mtklein6cfa73a2014-08-13 13:33:49 -07002716
dandovecfff212014-08-04 10:02:00 -07002717 LOOPER_END
2718}
2719
reeda8db7282015-07-07 10:22:31 -07002720void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002721 RETURN_ON_NULL(dr);
2722 if (x || y) {
2723 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2724 this->onDrawDrawable(dr, &matrix);
2725 } else {
2726 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002727 }
2728}
2729
reeda8db7282015-07-07 10:22:31 -07002730void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002731 RETURN_ON_NULL(dr);
2732 if (matrix && matrix->isIdentity()) {
2733 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002734 }
reede3b38ce2016-01-08 09:18:44 -08002735 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002736}
2737
2738void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002739 // drawable bounds are no longer reliable (e.g. android displaylist)
2740 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002741 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002742}
2743
reed71c3c762015-06-24 10:29:17 -07002744void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002745 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002746 const SkRect* cull, const SkPaint* paint) {
2747 if (cull && this->quickReject(*cull)) {
2748 return;
2749 }
2750
2751 SkPaint pnt;
2752 if (paint) {
2753 pnt = *paint;
2754 }
halcanary9d524f22016-03-29 09:03:52 -07002755
halcanary96fcdcc2015-08-27 07:41:13 -07002756 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002757 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002758 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002759 }
2760 LOOPER_END
2761}
2762
reedf70b5312016-03-04 16:36:20 -08002763void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2764 SkASSERT(key);
2765
2766 SkPaint paint;
2767 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2768 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002769 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002770 }
2771 LOOPER_END
2772}
2773
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774//////////////////////////////////////////////////////////////////////////////
2775// These methods are NOT virtual, and therefore must call back into virtual
2776// methods, rather than actually drawing themselves.
2777//////////////////////////////////////////////////////////////////////////////
2778
reed374772b2016-10-05 17:33:02 -07002779void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002780 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 SkPaint paint;
2782
2783 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002784 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002785 this->drawPaint(paint);
2786}
2787
2788void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002789 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002790 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2792}
2793
Mike Reed3661bc92017-02-22 13:21:42 -05002794void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002795 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002797
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798 pts[0].set(x0, y0);
2799 pts[1].set(x1, y1);
2800 this->drawPoints(kLines_PointMode, 2, pts, paint);
2801}
2802
Mike Reed3661bc92017-02-22 13:21:42 -05002803void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002804 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805 if (radius < 0) {
2806 radius = 0;
2807 }
2808
2809 SkRect r;
2810 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002811 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812}
2813
2814void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2815 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002816 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002818 SkRRect rrect;
2819 rrect.setRectXY(r, rx, ry);
2820 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002821 } else {
2822 this->drawRect(r, paint);
2823 }
2824}
2825
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2827 SkScalar sweepAngle, bool useCenter,
2828 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002829 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002830 if (oval.isEmpty() || !sweepAngle) {
2831 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002832 }
bsalomon21af9ca2016-08-25 12:29:23 -07002833 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002834}
2835
2836void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2837 const SkPath& path, SkScalar hOffset,
2838 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002839 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002841
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842 matrix.setTranslate(hOffset, vOffset);
2843 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2844}
2845
reed@android.comf76bacf2009-05-13 14:00:33 +00002846///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002847
2848/**
2849 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2850 * against the playback cost of recursing into the subpicture to get at its actual ops.
2851 *
2852 * For now we pick a conservatively small value, though measurement (and other heuristics like
2853 * the type of ops contained) may justify changing this value.
2854 */
2855#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002856
reedd5fa1a42014-08-09 11:08:05 -07002857void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002858 RETURN_ON_NULL(picture);
2859
reed1c2c4412015-04-30 13:09:24 -07002860 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002861 if (matrix && matrix->isIdentity()) {
2862 matrix = nullptr;
2863 }
2864 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2865 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2866 picture->playback(this);
2867 } else {
2868 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002869 }
2870}
robertphillips9b14f262014-06-04 05:40:44 -07002871
reedd5fa1a42014-08-09 11:08:05 -07002872void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2873 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002874 if (!paint || paint->canComputeFastBounds()) {
2875 SkRect bounds = picture->cullRect();
2876 if (paint) {
2877 paint->computeFastBounds(bounds, &bounds);
2878 }
2879 if (matrix) {
2880 matrix->mapRect(&bounds);
2881 }
2882 if (this->quickReject(bounds)) {
2883 return;
2884 }
2885 }
2886
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002887 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002888 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002889}
2890
vjiaoblack95302da2016-07-21 10:25:54 -07002891#ifdef SK_EXPERIMENTAL_SHADOWING
2892void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2893 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002894 const SkPaint* paint,
2895 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002896 RETURN_ON_NULL(picture);
2897
2898 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2899
vjiaoblacke6f5d562016-08-25 06:30:23 -07002900 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002901}
2902
2903void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2904 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002905 const SkPaint* paint,
2906 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002907 if (!paint || paint->canComputeFastBounds()) {
2908 SkRect bounds = picture->cullRect();
2909 if (paint) {
2910 paint->computeFastBounds(bounds, &bounds);
2911 }
2912 if (matrix) {
2913 matrix->mapRect(&bounds);
2914 }
2915 if (this->quickReject(bounds)) {
2916 return;
2917 }
2918 }
2919
2920 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2921
vjiaoblacke6f5d562016-08-25 06:30:23 -07002922 sk_sp<SkImage> povDepthMap;
2923 sk_sp<SkImage> diffuseMap;
2924
vjiaoblack904527d2016-08-09 09:32:09 -07002925 // povDepthMap
2926 {
2927 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002928 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2929 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002930 sk_sp<SkLights> povLight = builder.finish();
2931
2932 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2933 picture->cullRect().height(),
2934 kBGRA_8888_SkColorType,
2935 kOpaque_SkAlphaType);
2936
2937 // Create a new surface (that matches the backend of canvas)
2938 // to create the povDepthMap
2939 sk_sp<SkSurface> surf(this->makeSurface(info));
2940
2941 // Wrap another SPFCanvas around the surface
2942 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2943 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2944
2945 // set the depth map canvas to have the light as the user's POV
2946 depthMapCanvas->setLights(std::move(povLight));
2947
2948 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002949 povDepthMap = surf->makeImageSnapshot();
2950 }
2951
2952 // diffuseMap
2953 {
2954 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2955 picture->cullRect().height(),
2956 kBGRA_8888_SkColorType,
2957 kOpaque_SkAlphaType);
2958
2959 sk_sp<SkSurface> surf(this->makeSurface(info));
2960 surf->getCanvas()->drawPicture(picture);
2961
2962 diffuseMap = surf->makeImageSnapshot();
2963 }
vjiaoblack904527d2016-08-09 09:32:09 -07002964
2965 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
2966 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07002967 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
2968 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07002969
2970 // TODO: pass the depth to the shader in vertices, or uniforms
2971 // so we don't have to render depth and color separately
2972 for (int i = 0; i < fLights->numLights(); ++i) {
2973 // skip over ambient lights; they don't cast shadows
2974 // lights that have shadow maps do not need updating (because lights are immutable)
2975 sk_sp<SkImage> depthMap;
2976 SkISize shMapSize;
2977
2978 if (fLights->light(i).getShadowMap() != nullptr) {
2979 continue;
2980 }
2981
2982 if (fLights->light(i).isRadial()) {
2983 shMapSize.fHeight = 1;
2984 shMapSize.fWidth = (int) picture->cullRect().width();
2985
2986 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
2987 kBGRA_8888_SkColorType,
2988 kOpaque_SkAlphaType);
2989
2990 // Create new surface (that matches the backend of canvas)
2991 // for each shadow map
2992 sk_sp<SkSurface> surf(this->makeSurface(info));
2993
2994 // Wrap another SPFCanvas around the surface
2995 SkCanvas* depthMapCanvas = surf->getCanvas();
2996
2997 SkLights::Builder builder;
2998 builder.add(fLights->light(i));
2999 sk_sp<SkLights> curLight = builder.finish();
3000
3001 sk_sp<SkShader> shadowMapShader;
3002 shadowMapShader = SkRadialShadowMapShader::Make(
3003 povDepthShader, curLight,
3004 (int) picture->cullRect().width(),
3005 (int) picture->cullRect().height());
3006
3007 SkPaint shadowMapPaint;
3008 shadowMapPaint.setShader(std::move(shadowMapShader));
3009
3010 depthMapCanvas->setLights(curLight);
3011
3012 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3013 diffuseMap->height()),
3014 shadowMapPaint);
3015
3016 depthMap = surf->makeImageSnapshot();
3017
3018 } else {
3019 // TODO: compute the correct size of the depth map from the light properties
3020 // TODO: maybe add a kDepth_8_SkColorType
3021 // TODO: find actual max depth of picture
3022 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3023 fLights->light(i), 255,
3024 (int) picture->cullRect().width(),
3025 (int) picture->cullRect().height());
3026
3027 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3028 kBGRA_8888_SkColorType,
3029 kOpaque_SkAlphaType);
3030
3031 // Create a new surface (that matches the backend of canvas)
3032 // for each shadow map
3033 sk_sp<SkSurface> surf(this->makeSurface(info));
3034
3035 // Wrap another SPFCanvas around the surface
3036 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3037 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3038 depthMapCanvas->setShadowParams(params);
3039
3040 // set the depth map canvas to have the light we're drawing.
3041 SkLights::Builder builder;
3042 builder.add(fLights->light(i));
3043 sk_sp<SkLights> curLight = builder.finish();
3044 depthMapCanvas->setLights(std::move(curLight));
3045
3046 depthMapCanvas->drawPicture(picture);
3047 depthMap = surf->makeImageSnapshot();
3048 }
3049
3050 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3051 fLights->light(i).setShadowMap(std::move(depthMap));
3052 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3053 // we blur the variance map
3054 SkPaint blurPaint;
3055 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3056 params.fShadowRadius, nullptr));
3057
3058 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3059 kBGRA_8888_SkColorType,
3060 kOpaque_SkAlphaType);
3061
3062 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3063
3064 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3065
3066 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3067 }
3068 }
3069
3070 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003071 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3072 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003073 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003074 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003075 diffuseMap->height(),
3076 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003077
3078 shadowPaint.setShader(shadowShader);
3079
3080 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003081}
3082#endif
3083
reed@android.com8a1c16f2008-12-17 15:59:43 +00003084///////////////////////////////////////////////////////////////////////////////
3085///////////////////////////////////////////////////////////////////////////////
3086
reed3aafe112016-08-18 12:45:34 -07003087SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003088 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003089
3090 SkASSERT(canvas);
3091
reed3aafe112016-08-18 12:45:34 -07003092 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003093 fDone = !fImpl->next();
3094}
3095
3096SkCanvas::LayerIter::~LayerIter() {
3097 fImpl->~SkDrawIter();
3098}
3099
3100void SkCanvas::LayerIter::next() {
3101 fDone = !fImpl->next();
3102}
3103
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003104SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003105 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003106}
3107
3108const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003109 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003110}
3111
3112const SkPaint& SkCanvas::LayerIter::paint() const {
3113 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003114 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003115 paint = &fDefaultPaint;
3116 }
3117 return *paint;
3118}
3119
Mike Reeda1361362017-03-07 09:37:29 -05003120void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3121 return fImpl->fDevice->onAsRgnClip(rgn);
3122}
3123
reed@android.com8a1c16f2008-12-17 15:59:43 +00003124int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3125int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003126
3127///////////////////////////////////////////////////////////////////////////////
3128
Mike Reed93b1b4f2017-04-05 16:21:47 -04003129#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP
Mike Reed8310f0e2017-03-08 21:42:37 +00003130SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
Mike Reed93b1b4f2017-04-05 16:21:47 -04003131#endif
Mike Reed8310f0e2017-03-08 21:42:37 +00003132
3133///////////////////////////////////////////////////////////////////////////////
3134
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003135static bool supported_for_raster_canvas(const SkImageInfo& info) {
3136 switch (info.alphaType()) {
3137 case kPremul_SkAlphaType:
3138 case kOpaque_SkAlphaType:
3139 break;
3140 default:
3141 return false;
3142 }
3143
3144 switch (info.colorType()) {
3145 case kAlpha_8_SkColorType:
3146 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003147 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003148 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003149 break;
3150 default:
3151 return false;
3152 }
3153
3154 return true;
3155}
3156
Mike Reed5df49342016-11-12 08:06:55 -06003157std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3158 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003159 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003160 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003161 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003162
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003163 SkBitmap bitmap;
3164 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003165 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003166 }
Mike Reed5df49342016-11-12 08:06:55 -06003167 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003168}
reedd5fa1a42014-08-09 11:08:05 -07003169
3170///////////////////////////////////////////////////////////////////////////////
3171
3172SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003173 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003174 : fCanvas(canvas)
3175 , fSaveCount(canvas->getSaveCount())
3176{
bsalomon49f085d2014-09-05 13:34:00 -07003177 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003178 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003179 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003180 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003181 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003182 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003183 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003184 canvas->save();
3185 }
mtklein6cfa73a2014-08-13 13:33:49 -07003186
bsalomon49f085d2014-09-05 13:34:00 -07003187 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003188 canvas->concat(*matrix);
3189 }
3190}
3191
3192SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3193 fCanvas->restoreToCount(fSaveCount);
3194}
reede8f30622016-03-23 18:59:25 -07003195
Florin Malitaee424ac2016-12-01 12:47:59 -05003196///////////////////////////////////////////////////////////////////////////////
3197
3198SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3199 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3200
Florin Malita439ace92016-12-02 12:05:41 -05003201SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3202 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3203
Florin Malitaee424ac2016-12-01 12:47:59 -05003204SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3205 (void)this->INHERITED::getSaveLayerStrategy(rec);
3206 return kNoLayer_SaveLayerStrategy;
3207}
3208
3209///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003210
reed73603f32016-09-20 08:42:38 -07003211static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3212static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3213static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3214static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3215static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3216static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003217
3218///////////////////////////////////////////////////////////////////////////////////////////////////
3219
3220SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3221 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3222 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3223 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3224 SkIPoint origin = dev->getOrigin();
3225 SkMatrix ctm = this->getTotalMatrix();
3226 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3227
3228 SkIRect clip = fMCRec->fRasterClip.getBounds();
3229 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003230 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003231 clip.setEmpty();
3232 }
3233
3234 fAllocator->updateHandle(handle, ctm, clip);
3235 return handle;
3236 }
3237 return nullptr;
3238}
3239
3240static bool install(SkBitmap* bm, const SkImageInfo& info,
3241 const SkRasterHandleAllocator::Rec& rec) {
3242 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3243 rec.fReleaseProc, rec.fReleaseCtx);
3244}
3245
3246SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3247 SkBitmap* bm) {
3248 SkRasterHandleAllocator::Rec rec;
3249 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3250 return nullptr;
3251 }
3252 return rec.fHandle;
3253}
3254
3255std::unique_ptr<SkCanvas>
3256SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3257 const SkImageInfo& info, const Rec* rec) {
3258 if (!alloc || !supported_for_raster_canvas(info)) {
3259 return nullptr;
3260 }
3261
3262 SkBitmap bm;
3263 Handle hndl;
3264
3265 if (rec) {
3266 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3267 } else {
3268 hndl = alloc->allocBitmap(info, &bm);
3269 }
3270 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3271}