blob: 1b96f4934e5faa1411e9c114a4da60468892db83 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050026#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070027#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070028#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070029#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000030#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070031#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070035#include "SkShadowPaintFilterCanvas.h"
36#include "SkShadowShader.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000047#include "GrRenderTarget.h"
Brian Osman3b655982017-03-07 16:58:08 -050048#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050051#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050052#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
55
Mike Reed139e5e02017-03-08 11:29:33 -050056class SkNoPixelsDevice : public SkBaseDevice {
57public:
58 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
59 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
Mike Reed566e53c2017-03-10 10:49:45 -050060 {
Mike Reede393a622017-03-10 16:35:25 -050061 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
62 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050063 }
Mike Reed139e5e02017-03-08 11:29:33 -050064
65 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050066 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050067 this->privateResize(bounds.width(), bounds.height());
68 }
69
70protected:
71 // We don't track the clip at all (for performance), but we have to respond to some queries.
72 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
73 void onSave() override {}
74 void onRestore() override {}
75 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
76 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
77 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
78 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
79 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
80 bool onClipIsAA() const override { return false; }
81 void onAsRgnClip(SkRegion* rgn) const override {
82 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
83 }
84 ClipType onGetClipType() const override {
85 return kRect_ClipType;
86 }
87
88 void drawPaint(const SkPaint& paint) override {}
89 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
90 void drawRect(const SkRect&, const SkPaint&) override {}
91 void drawOval(const SkRect&, const SkPaint&) override {}
92 void drawRRect(const SkRRect&, const SkPaint&) override {}
93 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
94 void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {}
95 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
96 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
97 SkCanvas::SrcRectConstraint) override {}
98 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
99 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
100 const SkPaint&) override {}
101 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
Mike Reed2f6b5a42017-03-19 15:04:17 -0400102 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -0500103
104private:
105 typedef SkBaseDevice INHERITED;
106};
107
108///////////////////////////////////////////////////////////////////////////////////////////////////
109
reedc83a2972015-07-16 07:40:45 -0700110/*
111 * Return true if the drawing this rect would hit every pixels in the canvas.
112 *
113 * Returns false if
114 * - rect does not contain the canvas' bounds
115 * - paint is not fill
116 * - paint would blur or otherwise change the coverage of the rect
117 */
118bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
119 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700120 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
121 (int)kNone_ShaderOverrideOpacity,
122 "need_matching_enums0");
123 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
124 (int)kOpaque_ShaderOverrideOpacity,
125 "need_matching_enums1");
126 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
127 (int)kNotOpaque_ShaderOverrideOpacity,
128 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700129
130 const SkISize size = this->getBaseLayerSize();
131 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500132
133 // if we're clipped at all, we can't overwrite the entire surface
134 {
135 SkBaseDevice* base = this->getDevice();
136 SkBaseDevice* top = this->getTopDevice();
137 if (base != top) {
138 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
139 }
140 if (!base->clipIsWideOpen()) {
141 return false;
142 }
reedc83a2972015-07-16 07:40:45 -0700143 }
144
145 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700146 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700147 return false; // conservative
148 }
halcanaryc5769b22016-08-10 07:13:21 -0700149
150 SkRect devRect;
151 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
152 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700153 return false;
154 }
155 }
156
157 if (paint) {
158 SkPaint::Style paintStyle = paint->getStyle();
159 if (!(paintStyle == SkPaint::kFill_Style ||
160 paintStyle == SkPaint::kStrokeAndFill_Style)) {
161 return false;
162 }
163 if (paint->getMaskFilter() || paint->getLooper()
164 || paint->getPathEffect() || paint->getImageFilter()) {
165 return false; // conservative
166 }
167 }
168 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
169}
170
171///////////////////////////////////////////////////////////////////////////////////////////////////
172
reedd990e2f2014-12-22 11:58:30 -0800173static bool gIgnoreSaveLayerBounds;
174void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
175 gIgnoreSaveLayerBounds = ignore;
176}
177bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
178 return gIgnoreSaveLayerBounds;
179}
180
reed0acf1b42014-12-22 16:12:38 -0800181static bool gTreatSpriteAsBitmap;
182void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
183 gTreatSpriteAsBitmap = spriteAsBitmap;
184}
185bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
186 return gTreatSpriteAsBitmap;
187}
188
reed@google.comda17f752012-08-16 18:27:05 +0000189// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190//#define SK_TRACE_SAVERESTORE
191
192#ifdef SK_TRACE_SAVERESTORE
193 static int gLayerCounter;
194 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
195 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
196
197 static int gRecCounter;
198 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
199 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
200
201 static int gCanvasCounter;
202 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
203 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
204#else
205 #define inc_layer()
206 #define dec_layer()
207 #define inc_rec()
208 #define dec_rec()
209 #define inc_canvas()
210 #define dec_canvas()
211#endif
212
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000213typedef SkTLazy<SkPaint> SkLazyPaint;
214
reedc83a2972015-07-16 07:40:45 -0700215void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000216 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700217 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
218 ? SkSurface::kDiscard_ContentChangeMode
219 : SkSurface::kRetain_ContentChangeMode);
220 }
221}
222
223void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
224 ShaderOverrideOpacity overrideOpacity) {
225 if (fSurfaceBase) {
226 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
227 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
228 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
229 // and therefore we don't care which mode we're in.
230 //
231 if (fSurfaceBase->outstandingImageSnapshot()) {
232 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
233 mode = SkSurface::kDiscard_ContentChangeMode;
234 }
235 }
236 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000237 }
238}
239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000242/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 The clip/matrix/proc are fields that reflect the top of the save/restore
244 stack. Whenever the canvas changes, it marks a dirty flag, and then before
245 these are used (assuming we're not on a layer) we rebuild these cache
246 values: they reflect the top of the save stack, but translated and clipped
247 by the device's XY offset and bitmap-bounds.
248*/
249struct DeviceCM {
250 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000251 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000252 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000253 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700254 const SkMatrix* fMatrix;
255 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700256 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257
Mike Reeda1361362017-03-07 09:37:29 -0500258 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700259 : fNext(nullptr)
reed8c30a812016-04-20 16:36:51 -0700260 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700261 {
reed2c9e2002016-07-25 08:05:22 -0700262 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000263 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700264 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000265 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000267 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700268 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700269 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000270 }
reed@google.com4b226022011-01-11 18:32:13 +0000271
mtkleinfeaadee2015-04-08 11:25:48 -0700272 void reset(const SkIRect& bounds) {
273 SkASSERT(!fPaint);
274 SkASSERT(!fNext);
275 SkASSERT(fDevice);
276 fClip.setRect(bounds);
277 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278};
279
280/* This is the record we keep for each save/restore level in the stack.
281 Since a level optionally copies the matrix and/or stack, we have pointers
282 for these fields. If the value is copied for this level, the copy is
283 stored in the ...Storage field, and the pointer points to that. If the
284 value is not copied for this level, we ignore ...Storage, and just point
285 at the corresponding value in the previous level in the stack.
286*/
287class SkCanvas::MCRec {
288public:
reed1f836ee2014-07-07 07:49:34 -0700289 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700290 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291 /* If there are any layers in the stack, this points to the top-most
292 one that is at or below this level in the stack (so we know what
293 bitmap/device to draw into from this level. This value is NOT
294 reference counted, since the real owner is either our fLayer field,
295 or a previous one in a lower level.)
296 */
Mike Reeda1361362017-03-07 09:37:29 -0500297 DeviceCM* fTopLayer;
298 SkConservativeClip fRasterClip;
299 SkMatrix fMatrix;
300 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301
vjiaoblacke5de1302016-07-13 14:05:28 -0700302 // This is the current cumulative depth (aggregate of all done translateZ calls)
303 SkScalar fCurDrawDepth;
304
Mike Reeda1361362017-03-07 09:37:29 -0500305 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700306 fFilter = nullptr;
307 fLayer = nullptr;
308 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800309 fMatrix.reset();
310 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700311 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700312
reedd9544982014-09-09 18:46:22 -0700313 // don't bother initializing fNext
314 inc_rec();
315 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700316 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
317 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700318 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700319 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700320 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800321 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700322
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323 // don't bother initializing fNext
324 inc_rec();
325 }
326 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000327 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700328 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 dec_rec();
330 }
mtkleinfeaadee2015-04-08 11:25:48 -0700331
332 void reset(const SkIRect& bounds) {
333 SkASSERT(fLayer);
334 SkASSERT(fDeferredSaveCount == 0);
335
336 fMatrix.reset();
337 fRasterClip.setRect(bounds);
338 fLayer->reset(bounds);
339 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340};
341
Mike Reeda1361362017-03-07 09:37:29 -0500342class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343public:
Mike Reeda1361362017-03-07 09:37:29 -0500344 SkDrawIter(SkCanvas* canvas)
345 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
346 {}
reed@google.com4b226022011-01-11 18:32:13 +0000347
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000349 const DeviceCM* rec = fCurrLayer;
350 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 fDevice = rec->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 fPaint = rec->fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700354 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 return true;
356 }
357 return false;
358 }
reed@google.com4b226022011-01-11 18:32:13 +0000359
reed@google.com6f8f2922011-03-04 22:27:10 +0000360 int getX() const { return fDevice->getOrigin().x(); }
361 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000363
Mike Reed99330ba2017-02-22 11:01:08 -0500364 SkBaseDevice* fDevice;
365
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 const DeviceCM* fCurrLayer;
368 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369};
370
Mike Reed7627fa52017-02-08 10:07:53 -0500371#define FOR_EACH_TOP_DEVICE( code ) \
372 do { \
373 DeviceCM* layer = fMCRec->fTopLayer; \
374 while (layer) { \
375 SkBaseDevice* device = layer->fDevice; \
Mike Reedc42a1cd2017-02-14 14:25:14 -0500376 if (device) { \
377 code; \
378 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500379 layer = layer->fNext; \
380 } \
381 } while (0)
382
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383/////////////////////////////////////////////////////////////////////////////
384
reeddbc3cef2015-04-29 12:18:57 -0700385static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
386 return lazy->isValid() ? lazy->get() : lazy->set(orig);
387}
388
389/**
390 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700391 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700392 */
reedd053ce92016-03-22 10:17:23 -0700393static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700394 SkImageFilter* imgf = paint.getImageFilter();
395 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700396 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700397 }
398
reedd053ce92016-03-22 10:17:23 -0700399 SkColorFilter* imgCFPtr;
400 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700401 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700402 }
reedd053ce92016-03-22 10:17:23 -0700403 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700404
405 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700406 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700407 // there is no existing paint colorfilter, so we can just return the imagefilter's
408 return imgCF;
409 }
410
411 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
412 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700413 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700414}
415
senorblanco87e066e2015-10-28 11:23:36 -0700416/**
417 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
418 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
419 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
420 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
421 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
422 * conservative "effective" bounds based on the settings in the paint... with one exception. This
423 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
424 * deliberately ignored.
425 */
426static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
427 const SkRect& rawBounds,
428 SkRect* storage) {
429 SkPaint tmpUnfiltered(paint);
430 tmpUnfiltered.setImageFilter(nullptr);
431 if (tmpUnfiltered.canComputeFastBounds()) {
432 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
433 } else {
434 return rawBounds;
435 }
436}
437
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438class AutoDrawLooper {
439public:
senorblanco87e066e2015-10-28 11:23:36 -0700440 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
441 // paint. It's used to determine the size of the offscreen layer for filters.
442 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700443 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700444 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000445 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800446#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800448#else
449 fFilter = nullptr;
450#endif
reed4a8126e2014-09-22 07:29:03 -0700451 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000452 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700453 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000454 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000455
reedd053ce92016-03-22 10:17:23 -0700456 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700457 if (simplifiedCF) {
458 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700459 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700460 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700461 fPaint = paint;
462 }
463
464 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700465 /**
466 * We implement ImageFilters for a given draw by creating a layer, then applying the
467 * imagefilter to the pixels of that layer (its backing surface/image), and then
468 * we call restore() to xfer that layer to the main canvas.
469 *
470 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
471 * 2. Generate the src pixels:
472 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
473 * return (fPaint). We then draw the primitive (using srcover) into a cleared
474 * buffer/surface.
475 * 3. Restore the layer created in #1
476 * The imagefilter is passed the buffer/surface from the layer (now filled with the
477 * src pixels of the primitive). It returns a new "filtered" buffer, which we
478 * draw onto the previous layer using the xfermode from the original paint.
479 */
reed@google.com8926b162012-03-23 15:36:36 +0000480 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500481 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700482 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700483 SkRect storage;
484 if (rawBounds) {
485 // Make rawBounds include all paint outsets except for those due to image filters.
486 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
487 }
reedbfd5f172016-01-07 11:28:08 -0800488 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700489 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700490 fTempLayerForImageFilter = true;
491 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000492 }
493
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000494 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500495 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000496 fIsSimple = false;
497 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700498 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000499 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700500 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000501 }
502 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000503
reed@android.com8a1c16f2008-12-17 15:59:43 +0000504 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700505 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000506 fCanvas->internalRestore();
507 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000508 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000510
reed@google.com4e2b3d32011-04-07 14:18:59 +0000511 const SkPaint& paint() const {
512 SkASSERT(fPaint);
513 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@google.com129ec222012-05-15 13:24:09 +0000516 bool next(SkDrawFilter::Type drawType) {
517 if (fDone) {
518 return false;
519 } else if (fIsSimple) {
520 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000521 return !fPaint->nothingToDraw();
522 } else {
523 return this->doNext(drawType);
524 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000525 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000526
reed@android.com8a1c16f2008-12-17 15:59:43 +0000527private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500528 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700529 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000530 SkCanvas* fCanvas;
531 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000532 SkDrawFilter* fFilter;
533 const SkPaint* fPaint;
534 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700535 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000536 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000537 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000538 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500539 char fStorage[48];
540 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000541
542 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000543};
544
reed@google.com129ec222012-05-15 13:24:09 +0000545bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700546 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000547 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700548 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000549
reeddbc3cef2015-04-29 12:18:57 -0700550 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
551 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000552
reed5c476fb2015-04-20 08:04:21 -0700553 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700554 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700555 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000556 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000557
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000558 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000559 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000560 return false;
561 }
562 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000563 if (!fFilter->filter(paint, drawType)) {
564 fDone = true;
565 return false;
566 }
halcanary96fcdcc2015-08-27 07:41:13 -0700567 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000568 // no looper means we only draw once
569 fDone = true;
570 }
571 }
572 fPaint = paint;
573
574 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000575 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000576 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000577 }
578
579 // call this after any possible paint modifiers
580 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700581 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000582 return false;
583 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000584 return true;
585}
586
reed@android.com8a1c16f2008-12-17 15:59:43 +0000587////////// macros to place around the internal draw calls //////////////////
588
reed3aafe112016-08-18 12:45:34 -0700589#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
590 this->predrawNotify(); \
591 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
592 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800593 SkDrawIter iter(this);
594
595
reed@google.com8926b162012-03-23 15:36:36 +0000596#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000597 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700598 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000599 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000600 SkDrawIter iter(this);
601
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000602#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000603 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700604 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000605 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000607
reedc83a2972015-07-16 07:40:45 -0700608#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
609 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700610 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700611 while (looper.next(type)) { \
612 SkDrawIter iter(this);
613
reed@google.com4e2b3d32011-04-07 14:18:59 +0000614#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615
616////////////////////////////////////////////////////////////////////////////
617
msarettfbfa2582016-08-12 08:29:08 -0700618static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
619 if (bounds.isEmpty()) {
620 return SkRect::MakeEmpty();
621 }
622
623 // Expand bounds out by 1 in case we are anti-aliasing. We store the
624 // bounds as floats to enable a faster quick reject implementation.
625 SkRect dst;
626 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
627 return dst;
628}
629
mtkleinfeaadee2015-04-08 11:25:48 -0700630void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
631 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700632 fMCRec->reset(bounds);
633
634 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500635 // know that the device is a SkNoPixelsDevice.
636 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice)->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700637 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700638 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700639}
640
reedd9544982014-09-09 18:46:22 -0700641SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800642 if (device && device->forceConservativeRasterClip()) {
643 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
644 }
reed42b73eb2015-11-20 13:42:42 -0800645
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000646 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800647 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700648 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700649#ifdef SK_EXPERIMENTAL_SHADOWING
650 fLights = nullptr;
651#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000652
653 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500654 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500655 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700656 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657
reeda499f902015-05-01 09:34:31 -0700658 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
659 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Mike Reeda1361362017-03-07 09:37:29 -0500660 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700661
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663
halcanary96fcdcc2015-08-27 07:41:13 -0700664 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000665
reedf92c8662014-08-18 08:02:43 -0700666 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700667 // The root device and the canvas should always have the same pixel geometry
668 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700669 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800670 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700671 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500672
Mike Reedc42a1cd2017-02-14 14:25:14 -0500673 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700674 }
msarettfbfa2582016-08-12 08:29:08 -0700675
reedf92c8662014-08-18 08:02:43 -0700676 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677}
678
reed@google.comcde92112011-07-06 20:00:52 +0000679SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000680 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700681 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000682{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000683 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000684
halcanary96fcdcc2015-08-27 07:41:13 -0700685 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000686}
687
reed96a857e2015-01-25 10:33:58 -0800688SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000689 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800690 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000691{
692 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700693
Mike Reed566e53c2017-03-10 10:49:45 -0500694 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700695 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700696}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000697
reed78e27682014-11-19 08:04:34 -0800698SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700699 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700700 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700701{
702 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700703
Mike Reed566e53c2017-03-10 10:49:45 -0500704 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
705 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700706}
707
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000708SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000709 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700710 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000711{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700713
reedd9544982014-09-09 18:46:22 -0700714 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715}
716
robertphillipsfcf78292015-06-19 11:49:52 -0700717SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
718 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700719 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700720{
721 inc_canvas();
722
723 this->init(device, flags);
724}
725
reed4a8126e2014-09-22 07:29:03 -0700726SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700727 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700728 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700729{
730 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700731
Hal Canary704cd322016-11-07 14:13:52 -0500732 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
733 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700734}
reed29c857d2014-09-21 10:25:07 -0700735
Mike Reed356f7c22017-01-10 11:58:39 -0500736SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
737 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700738 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
739 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500740 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700741{
742 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700743
Mike Reed356f7c22017-01-10 11:58:39 -0500744 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500745 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746}
747
Mike Reed356f7c22017-01-10 11:58:39 -0500748SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
749
Matt Sarett31f99ce2017-04-11 08:46:01 -0400750#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
751SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
752 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
753 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
754 , fAllocator(nullptr)
755{
756 inc_canvas();
757
758 SkBitmap tmp(bitmap);
759 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
760 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
761 this->init(device.get(), kDefault_InitFlags);
762}
763#endif
764
reed@android.com8a1c16f2008-12-17 15:59:43 +0000765SkCanvas::~SkCanvas() {
766 // free up the contents of our deque
767 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000768
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769 this->internalRestore(); // restore the last, since we're going away
770
halcanary385fe4d2015-08-26 13:07:48 -0700771 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000772
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 dec_canvas();
774}
775
fmalita53d9f1c2016-01-25 06:23:54 -0800776#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777SkDrawFilter* SkCanvas::getDrawFilter() const {
778 return fMCRec->fFilter;
779}
780
781SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700782 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
784 return filter;
785}
fmalita77650002016-01-21 18:47:11 -0800786#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000788SkMetaData& SkCanvas::getMetaData() {
789 // metadata users are rare, so we lazily allocate it. If that changes we
790 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700791 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000792 fMetaData = new SkMetaData;
793 }
794 return *fMetaData;
795}
796
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797///////////////////////////////////////////////////////////////////////////////
798
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000799void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700800 this->onFlush();
801}
802
803void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000804 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000805 if (device) {
806 device->flush();
807 }
808}
809
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000810SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000811 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000812 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
813}
814
senorblancoafc7cce2016-02-02 18:44:15 -0800815SkIRect SkCanvas::getTopLayerBounds() const {
816 SkBaseDevice* d = this->getTopDevice();
817 if (!d) {
818 return SkIRect::MakeEmpty();
819 }
820 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
821}
822
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000823SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000825 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826 SkASSERT(rec && rec->fLayer);
827 return rec->fLayer->fDevice;
828}
829
Florin Malita0ed3b642017-01-13 16:56:38 +0000830SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000831 return fMCRec->fTopLayer->fDevice;
832}
833
Mike Reed12e946b2017-04-17 10:53:29 -0400834#ifdef SK_SUPPORT_LEGACY_CANVAS_READPIXELS
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000835bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000836 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700837 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700838 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000839 return false;
840 }
841 weAllocated = true;
842 }
843
reedcf01e312015-05-23 19:14:51 -0700844 SkAutoPixmapUnlock unlocker;
845 if (bitmap->requestLock(&unlocker)) {
846 const SkPixmap& pm = unlocker.pixmap();
847 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
848 return true;
849 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000850 }
851
852 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500853 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000854 }
855 return false;
856}
reed@google.com51df9e32010-12-23 19:29:18 +0000857
bsalomon@google.comc6980972011-11-02 19:57:21 +0000858bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000859 SkIRect r = srcRect;
860 const SkISize size = this->getBaseLayerSize();
861 if (!r.intersect(0, 0, size.width(), size.height())) {
862 bitmap->reset();
863 return false;
864 }
865
reed84825042014-09-02 12:50:45 -0700866 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000867 // bitmap will already be reset.
868 return false;
869 }
870 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
871 bitmap->reset();
872 return false;
873 }
874 return true;
875}
Mike Reed12e946b2017-04-17 10:53:29 -0400876#endif
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000877
reed96472de2014-12-10 09:53:42 -0800878bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000879 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000880 if (!device) {
881 return false;
882 }
mtkleinf0f14112014-12-12 08:46:25 -0800883
Matt Sarett03dd6d52017-01-23 12:15:09 -0500884 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000885}
886
Mike Reed12e946b2017-04-17 10:53:29 -0400887bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
888 return pm.addr() && this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y);
889}
890
891bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
892 SkPixmap pm;
893 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
894}
895
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000896bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700897 SkAutoPixmapUnlock unlocker;
898 if (bitmap.requestLock(&unlocker)) {
899 const SkPixmap& pm = unlocker.pixmap();
900 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000901 }
902 return false;
903}
904
Matt Sarett03dd6d52017-01-23 12:15:09 -0500905bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000906 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000907 SkBaseDevice* device = this->getDevice();
908 if (!device) {
909 return false;
910 }
911
Matt Sarett03dd6d52017-01-23 12:15:09 -0500912 // This check gives us an early out and prevents generation ID churn on the surface.
913 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
914 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
915 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
916 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000917 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000918
Matt Sarett03dd6d52017-01-23 12:15:09 -0500919 // Tell our owning surface to bump its generation ID.
920 const bool completeOverwrite =
921 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700922 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700923
Matt Sarett03dd6d52017-01-23 12:15:09 -0500924 // This can still fail, most notably in the case of a invalid color type or alpha type
925 // conversion. We could pull those checks into this function and avoid the unnecessary
926 // generation ID bump. But then we would be performing those checks twice, since they
927 // are also necessary at the bitmap/pixmap entry points.
928 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000929}
reed@google.com51df9e32010-12-23 19:29:18 +0000930
reed@android.com8a1c16f2008-12-17 15:59:43 +0000931//////////////////////////////////////////////////////////////////////////////
932
reed2ff1fce2014-12-11 07:07:37 -0800933void SkCanvas::checkForDeferredSave() {
934 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800935 this->doSave();
936 }
937}
938
reedf0090cb2014-11-26 08:55:51 -0800939int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800940#ifdef SK_DEBUG
941 int count = 0;
942 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
943 for (;;) {
944 const MCRec* rec = (const MCRec*)iter.next();
945 if (!rec) {
946 break;
947 }
948 count += 1 + rec->fDeferredSaveCount;
949 }
950 SkASSERT(count == fSaveCount);
951#endif
952 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800953}
954
955int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800956 fSaveCount += 1;
957 fMCRec->fDeferredSaveCount += 1;
958 return this->getSaveCount() - 1; // return our prev value
959}
960
961void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800962 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700963
964 SkASSERT(fMCRec->fDeferredSaveCount > 0);
965 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800966 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800967}
968
969void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800970 if (fMCRec->fDeferredSaveCount > 0) {
971 SkASSERT(fSaveCount > 1);
972 fSaveCount -= 1;
973 fMCRec->fDeferredSaveCount -= 1;
974 } else {
975 // check for underflow
976 if (fMCStack.count() > 1) {
977 this->willRestore();
978 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700979 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800980 this->internalRestore();
981 this->didRestore();
982 }
reedf0090cb2014-11-26 08:55:51 -0800983 }
984}
985
986void SkCanvas::restoreToCount(int count) {
987 // sanity check
988 if (count < 1) {
989 count = 1;
990 }
mtkleinf0f14112014-12-12 08:46:25 -0800991
reedf0090cb2014-11-26 08:55:51 -0800992 int n = this->getSaveCount() - count;
993 for (int i = 0; i < n; ++i) {
994 this->restore();
995 }
996}
997
reed2ff1fce2014-12-11 07:07:37 -0800998void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000999 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001000 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001001 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001002
Mike Reedc42a1cd2017-02-14 14:25:14 -05001003 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004}
1005
reed4960eee2015-12-18 07:09:18 -08001006bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001007 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001008}
1009
reed4960eee2015-12-18 07:09:18 -08001010bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001011 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001012 SkIRect clipBounds = this->getDeviceClipBounds();
1013 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001014 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001015 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001016
reed96e657d2015-03-10 17:30:07 -07001017 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1018
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001019 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001020 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001021 if (bounds && !imageFilter->canComputeFastBounds()) {
1022 bounds = nullptr;
1023 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001024 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001025 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001026 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001028
reed96e657d2015-03-10 17:30:07 -07001029 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001030 r.roundOut(&ir);
1031 // early exit if the layer's bounds are clipped out
1032 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001033 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -05001034 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -07001035 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001036 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001037 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001038 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001039 }
1040 } else { // no user bounds, so just use the clip
1041 ir = clipBounds;
1042 }
reed180aec42015-03-11 10:39:04 -07001043 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044
reed4960eee2015-12-18 07:09:18 -08001045 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001046 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -07001047 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001048 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001049 }
1050
1051 if (intersection) {
1052 *intersection = ir;
1053 }
1054 return true;
1055}
1056
reed4960eee2015-12-18 07:09:18 -08001057
reed4960eee2015-12-18 07:09:18 -08001058int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1059 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001060}
1061
reed70ee31b2015-12-10 13:44:45 -08001062int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001063 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1064}
1065
1066int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1067 SaveLayerRec rec(origRec);
1068 if (gIgnoreSaveLayerBounds) {
1069 rec.fBounds = nullptr;
1070 }
1071 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1072 fSaveCount += 1;
1073 this->internalSaveLayer(rec, strategy);
1074 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001075}
1076
reeda2217ef2016-07-20 06:04:34 -07001077void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001078 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001079 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001080 SkDraw draw;
1081 SkRasterClip rc;
1082 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1083 if (!dst->accessPixels(&draw.fDst)) {
1084 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001085 }
reeda2217ef2016-07-20 06:04:34 -07001086 draw.fMatrix = &SkMatrix::I();
1087 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001088
1089 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001090 if (filter) {
1091 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1092 }
reeda2217ef2016-07-20 06:04:34 -07001093
Mike Reedc42a1cd2017-02-14 14:25:14 -05001094 int x = src->getOrigin().x() - dstOrigin.x();
1095 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001096 auto special = src->snapSpecial();
1097 if (special) {
Mike Reeda1361362017-03-07 09:37:29 -05001098 dst->drawSpecial(special.get(), x, y, p);
reeda2217ef2016-07-20 06:04:34 -07001099 }
robertphillips7354a4b2015-12-16 05:08:27 -08001100}
reed70ee31b2015-12-10 13:44:45 -08001101
reed129ed1c2016-02-22 06:42:31 -08001102static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1103 const SkPaint* paint) {
1104 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1105 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001106 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001107 const bool hasImageFilter = paint && paint->getImageFilter();
1108
1109 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1110 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1111 // force to L32
1112 return SkImageInfo::MakeN32(w, h, alphaType);
1113 } else {
1114 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001115 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001116 }
1117}
1118
reed4960eee2015-12-18 07:09:18 -08001119void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1120 const SkRect* bounds = rec.fBounds;
1121 const SkPaint* paint = rec.fPaint;
1122 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1123
reed8c30a812016-04-20 16:36:51 -07001124 SkLazyPaint lazyP;
1125 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1126 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001127 SkMatrix remainder;
1128 SkSize scale;
1129 /*
1130 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1131 * but they do handle scaling. To accommodate this, we do the following:
1132 *
1133 * 1. Stash off the current CTM
1134 * 2. Decompose the CTM into SCALE and REMAINDER
1135 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1136 * contains the REMAINDER
1137 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1138 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1139 * of the original imagefilter, and draw that (via drawSprite)
1140 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1141 *
1142 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1143 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1144 */
reed96a04f32016-04-25 09:25:15 -07001145 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001146 stashedMatrix.decomposeScale(&scale, &remainder))
1147 {
1148 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1149 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1150 SkPaint* p = lazyP.set(*paint);
1151 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1152 SkFilterQuality::kLow_SkFilterQuality,
1153 sk_ref_sp(imageFilter)));
1154 imageFilter = p->getImageFilter();
1155 paint = p;
1156 }
reed8c30a812016-04-20 16:36:51 -07001157
junov@chromium.orga907ac32012-02-24 21:54:07 +00001158 // do this before we create the layer. We don't call the public save() since
1159 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001160 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001161
junov@chromium.orga907ac32012-02-24 21:54:07 +00001162 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001163 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001164 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001165 }
1166
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001167 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1168 // the clipRectBounds() call above?
1169 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001170 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001171 }
1172
reed4960eee2015-12-18 07:09:18 -08001173 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001174 SkPixelGeometry geo = fProps.pixelGeometry();
1175 if (paint) {
reed76033be2015-03-14 10:54:31 -07001176 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001177 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001178 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001179 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001180 }
1181 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182
robertphillips5139e502016-07-19 05:10:40 -07001183 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001184 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001185 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001186 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001187 }
reedb2db8982014-11-13 12:41:02 -08001188
robertphillips5139e502016-07-19 05:10:40 -07001189 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001190 paint);
1191
Hal Canary704cd322016-11-07 14:13:52 -05001192 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001193 {
reed70ee31b2015-12-10 13:44:45 -08001194 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001195 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001196 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001197 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001198 preserveLCDText,
1199 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001200 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1201 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001202 return;
reed61f501f2015-04-29 08:34:00 -07001203 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001204 }
Hal Canary704cd322016-11-07 14:13:52 -05001205 DeviceCM* layer =
Mike Reeda1361362017-03-07 09:37:29 -05001206 new DeviceCM(newDevice.get(), paint, this, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001207
Mike Reedb43a3e02017-02-11 10:18:58 -05001208 // only have a "next" if this new layer doesn't affect the clip (rare)
1209 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210 fMCRec->fLayer = layer;
1211 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001212
Mike Reedc61abee2017-02-28 17:45:27 -05001213 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001214 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001215 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001216 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001217
Mike Reedc42a1cd2017-02-14 14:25:14 -05001218 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1219
1220 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1221 if (layer->fNext) {
1222 // need to punch a hole in the previous device, so we don't draw there, given that
1223 // the new top-layer will allow drawing to happen "below" it.
1224 SkRegion hole(ir);
1225 do {
1226 layer = layer->fNext;
1227 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1228 } while (layer->fNext);
1229 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230}
1231
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001232int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001233 if (0xFF == alpha) {
1234 return this->saveLayer(bounds, nullptr);
1235 } else {
1236 SkPaint tmpPaint;
1237 tmpPaint.setAlpha(alpha);
1238 return this->saveLayer(bounds, &tmpPaint);
1239 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001240}
1241
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242void SkCanvas::internalRestore() {
1243 SkASSERT(fMCStack.count() != 0);
1244
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001245 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246 DeviceCM* layer = fMCRec->fLayer; // may be null
1247 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001248 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249
1250 // now do the normal restore()
1251 fMCRec->~MCRec(); // balanced in save()
1252 fMCStack.pop_back();
1253 fMCRec = (MCRec*)fMCStack.back();
1254
Mike Reedc42a1cd2017-02-14 14:25:14 -05001255 if (fMCRec) {
1256 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1257 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001258
reed@android.com8a1c16f2008-12-17 15:59:43 +00001259 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1260 since if we're being recorded, we don't want to record this (the
1261 recorder will have already recorded the restore).
1262 */
bsalomon49f085d2014-09-05 13:34:00 -07001263 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001264 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001265 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001266 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001267 // restore what we smashed in internalSaveLayer
1268 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001269 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001270 delete layer;
reedb679ca82015-04-07 04:40:48 -07001271 } else {
1272 // we're at the root
reeda499f902015-05-01 09:34:31 -07001273 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001274 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001275 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001277 }
msarettfbfa2582016-08-12 08:29:08 -07001278
1279 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001280 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001281 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1282 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283}
1284
reede8f30622016-03-23 18:59:25 -07001285sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001286 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001287 props = &fProps;
1288 }
1289 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001290}
1291
reede8f30622016-03-23 18:59:25 -07001292sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001293 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001294 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001295}
1296
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001297SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001298 return this->onImageInfo();
1299}
1300
1301SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001302 SkBaseDevice* dev = this->getDevice();
1303 if (dev) {
1304 return dev->imageInfo();
1305 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001306 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001307 }
1308}
1309
brianosman898235c2016-04-06 07:38:23 -07001310bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001311 return this->onGetProps(props);
1312}
1313
1314bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001315 SkBaseDevice* dev = this->getDevice();
1316 if (dev) {
1317 if (props) {
1318 *props = fProps;
1319 }
1320 return true;
1321 } else {
1322 return false;
1323 }
1324}
1325
reed6ceeebd2016-03-09 14:26:26 -08001326bool SkCanvas::peekPixels(SkPixmap* pmap) {
1327 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001328}
1329
reed884e97c2015-05-26 11:31:54 -07001330bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001331 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001332 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001333}
1334
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001335void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001336 SkPixmap pmap;
1337 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001338 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001339 }
1340 if (info) {
1341 *info = pmap.info();
1342 }
1343 if (rowBytes) {
1344 *rowBytes = pmap.rowBytes();
1345 }
1346 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001347 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001348 }
reed884e97c2015-05-26 11:31:54 -07001349 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001350}
1351
reed884e97c2015-05-26 11:31:54 -07001352bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001353 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001354 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001355}
1356
reed@android.com8a1c16f2008-12-17 15:59:43 +00001357/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001358
reed7503d602016-07-15 14:23:29 -07001359void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001360 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001361 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001362 paint = &tmp;
1363 }
reed@google.com4b226022011-01-11 18:32:13 +00001364
reed@google.com8926b162012-03-23 15:36:36 +00001365 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001366
reed@android.com8a1c16f2008-12-17 15:59:43 +00001367 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001368 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001369 paint = &looper.paint();
1370 SkImageFilter* filter = paint->getImageFilter();
1371 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001372 if (filter) {
1373 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1374 if (specialImage) {
Mike Reeda1361362017-03-07 09:37:29 -05001375 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint);
Robert Phillips833dcf42016-11-18 08:44:13 -05001376 }
reed@google.com76dd2772012-01-05 21:15:07 +00001377 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001378 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001379 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001380 }
reeda2217ef2016-07-20 06:04:34 -07001381
reed@google.com4e2b3d32011-04-07 14:18:59 +00001382 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383}
1384
reed32704672015-12-16 08:27:10 -08001385/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001386
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001387void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001388 if (dx || dy) {
1389 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001390 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001391
reedfe69b502016-09-12 06:31:48 -07001392 // Translate shouldn't affect the is-scale-translateness of the matrix.
1393 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001394
Mike Reedc42a1cd2017-02-14 14:25:14 -05001395 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001396
reedfe69b502016-09-12 06:31:48 -07001397 this->didTranslate(dx,dy);
1398 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001399}
1400
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001401void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001402 SkMatrix m;
1403 m.setScale(sx, sy);
1404 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001405}
1406
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001407void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001408 SkMatrix m;
1409 m.setRotate(degrees);
1410 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001411}
1412
bungeman7438bfc2016-07-12 15:01:19 -07001413void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1414 SkMatrix m;
1415 m.setRotate(degrees, px, py);
1416 this->concat(m);
1417}
1418
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001419void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001420 SkMatrix m;
1421 m.setSkew(sx, sy);
1422 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001423}
1424
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001425void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001426 if (matrix.isIdentity()) {
1427 return;
1428 }
1429
reed2ff1fce2014-12-11 07:07:37 -08001430 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001431 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001432 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001433
Mike Reed7627fa52017-02-08 10:07:53 -05001434 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001435
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001436 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001437}
1438
reed8c30a812016-04-20 16:36:51 -07001439void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001440 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001441 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001442
Mike Reedc42a1cd2017-02-14 14:25:14 -05001443 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001444}
1445
1446void SkCanvas::setMatrix(const SkMatrix& matrix) {
1447 this->checkForDeferredSave();
1448 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001449 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450}
1451
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001453 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454}
1455
vjiaoblack95302da2016-07-21 10:25:54 -07001456#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001457void SkCanvas::translateZ(SkScalar z) {
1458 this->checkForDeferredSave();
1459 this->fMCRec->fCurDrawDepth += z;
1460 this->didTranslateZ(z);
1461}
1462
1463SkScalar SkCanvas::getZ() const {
1464 return this->fMCRec->fCurDrawDepth;
1465}
1466
vjiaoblack95302da2016-07-21 10:25:54 -07001467void SkCanvas::setLights(sk_sp<SkLights> lights) {
1468 this->fLights = lights;
1469}
1470
1471sk_sp<SkLights> SkCanvas::getLights() const {
1472 return this->fLights;
1473}
1474#endif
1475
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476//////////////////////////////////////////////////////////////////////////////
1477
Mike Reedc1f77742016-12-09 09:00:50 -05001478void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001479 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001480 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1481 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001482}
1483
Mike Reedc1f77742016-12-09 09:00:50 -05001484void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001485 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001486
Mike Reed7627fa52017-02-08 10:07:53 -05001487 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001488
reedc64eff52015-11-21 12:39:45 -08001489 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001490 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1491 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001492 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001493}
1494
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001495void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1496 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001497 if (fClipRestrictionRect.isEmpty()) {
1498 // we notify the device, but we *dont* resolve deferred saves (since we're just
1499 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001500 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001501 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001502 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001503 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001504 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001505 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001506 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1507 }
1508}
1509
Mike Reedc1f77742016-12-09 09:00:50 -05001510void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001511 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001512 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001513 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001514 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1515 } else {
1516 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001517 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001518}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001519
Mike Reedc1f77742016-12-09 09:00:50 -05001520void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001521 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001522
Brian Salomona3b45d42016-10-03 11:36:16 -04001523 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001524
Mike Reed7627fa52017-02-08 10:07:53 -05001525 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001526
Brian Salomona3b45d42016-10-03 11:36:16 -04001527 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1528 isAA);
1529 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001530}
1531
Mike Reedc1f77742016-12-09 09:00:50 -05001532void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001533 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001534 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001535
1536 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1537 SkRect r;
1538 if (path.isRect(&r)) {
1539 this->onClipRect(r, op, edgeStyle);
1540 return;
1541 }
1542 SkRRect rrect;
1543 if (path.isOval(&r)) {
1544 rrect.setOval(r);
1545 this->onClipRRect(rrect, op, edgeStyle);
1546 return;
1547 }
1548 if (path.isRRect(&rrect)) {
1549 this->onClipRRect(rrect, op, edgeStyle);
1550 return;
1551 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001552 }
robertphillips39f05382015-11-24 09:30:12 -08001553
1554 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001555}
1556
Mike Reedc1f77742016-12-09 09:00:50 -05001557void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001558 AutoValidateClip avc(this);
1559
Brian Salomona3b45d42016-10-03 11:36:16 -04001560 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001561
Mike Reed7627fa52017-02-08 10:07:53 -05001562 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001563
Brian Salomona3b45d42016-10-03 11:36:16 -04001564 const SkPath* rasterClipPath = &path;
1565 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001566 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1567 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001568 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001569}
1570
Mike Reedc1f77742016-12-09 09:00:50 -05001571void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001572 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001573 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001574}
1575
Mike Reedc1f77742016-12-09 09:00:50 -05001576void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001577 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001578
reed@google.com5c3d1472011-02-22 19:12:23 +00001579 AutoValidateClip avc(this);
1580
reed73603f32016-09-20 08:42:38 -07001581 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001582 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001583}
1584
reed@google.com819c9212011-02-23 18:56:55 +00001585#ifdef SK_DEBUG
1586void SkCanvas::validateClip() const {
1587 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001588 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001589 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001590 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001591 return;
1592 }
reed@google.com819c9212011-02-23 18:56:55 +00001593}
1594#endif
1595
Mike Reeda1361362017-03-07 09:37:29 -05001596bool SkCanvas::androidFramework_isClipAA() const {
1597 bool containsAA = false;
1598
1599 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1600
1601 return containsAA;
1602}
1603
1604class RgnAccumulator {
1605 SkRegion* fRgn;
1606public:
1607 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1608 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1609 SkIPoint origin = device->getOrigin();
1610 if (origin.x() | origin.y()) {
1611 rgn->translate(origin.x(), origin.y());
1612 }
1613 fRgn->op(*rgn, SkRegion::kUnion_Op);
1614 }
1615};
1616
1617void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1618 RgnAccumulator accum(rgn);
1619 SkRegion tmp;
1620
1621 rgn->setEmpty();
1622 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001623}
1624
reed@google.com5c3d1472011-02-22 19:12:23 +00001625///////////////////////////////////////////////////////////////////////////////
1626
reed@google.com754de5f2014-02-24 19:38:20 +00001627bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001628 return fMCRec->fRasterClip.isEmpty();
1629
1630 // TODO: should we only use the conservative answer in a recording canvas?
1631#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001632 SkBaseDevice* dev = this->getTopDevice();
1633 // if no device we return true
1634 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001635#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001636}
1637
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001638bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001639 SkBaseDevice* dev = this->getTopDevice();
1640 // if no device we return false
1641 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001642}
1643
msarettfbfa2582016-08-12 08:29:08 -07001644static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1645#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1646 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1647 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1648 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1649 return 0xF != _mm_movemask_ps(mask);
1650#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1651 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1652 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1653 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1654 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1655#else
1656 SkRect devRectAsRect;
1657 SkRect devClipAsRect;
1658 devRect.store(&devRectAsRect.fLeft);
1659 devClip.store(&devClipAsRect.fLeft);
1660 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1661#endif
1662}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001663
msarettfbfa2582016-08-12 08:29:08 -07001664// It's important for this function to not be inlined. Otherwise the compiler will share code
1665// between the fast path and the slow path, resulting in two slow paths.
1666static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1667 const SkMatrix& matrix) {
1668 SkRect deviceRect;
1669 matrix.mapRect(&deviceRect, src);
1670 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1671}
1672
1673bool SkCanvas::quickReject(const SkRect& src) const {
1674#ifdef SK_DEBUG
1675 // Verify that fDeviceClipBounds are set properly.
1676 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001677 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001678 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001679 } else {
msarettfbfa2582016-08-12 08:29:08 -07001680 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681 }
msarettfbfa2582016-08-12 08:29:08 -07001682
msarett9637ea92016-08-18 14:03:30 -07001683 // Verify that fIsScaleTranslate is set properly.
1684 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001685#endif
1686
msarett9637ea92016-08-18 14:03:30 -07001687 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001688 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1689 }
1690
1691 // We inline the implementation of mapScaleTranslate() for the fast path.
1692 float sx = fMCRec->fMatrix.getScaleX();
1693 float sy = fMCRec->fMatrix.getScaleY();
1694 float tx = fMCRec->fMatrix.getTranslateX();
1695 float ty = fMCRec->fMatrix.getTranslateY();
1696 Sk4f scale(sx, sy, sx, sy);
1697 Sk4f trans(tx, ty, tx, ty);
1698
1699 // Apply matrix.
1700 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1701
1702 // Make sure left < right, top < bottom.
1703 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1704 Sk4f min = Sk4f::Min(ltrb, rblt);
1705 Sk4f max = Sk4f::Max(ltrb, rblt);
1706 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1707 // ARM this sequence generates the fastest (a single instruction).
1708 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1709
1710 // Check if the device rect is NaN or outside the clip.
1711 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001712}
1713
reed@google.com3b3e8952012-08-16 20:53:31 +00001714bool SkCanvas::quickReject(const SkPath& path) const {
1715 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001716}
1717
Mike Reed42e8c532017-01-23 14:09:13 -05001718SkRect SkCanvas::onGetLocalClipBounds() const {
1719 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001720 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001721 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001722 }
1723
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001724 SkMatrix inverse;
1725 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001726 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001727 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001728 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001729
Mike Reed42e8c532017-01-23 14:09:13 -05001730 SkRect bounds;
1731 SkRect r;
1732 // adjust it outwards in case we are antialiasing
1733 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001734
Mike Reed42e8c532017-01-23 14:09:13 -05001735 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1736 ibounds.fRight + inset, ibounds.fBottom + inset);
1737 inverse.mapRect(&bounds, r);
1738 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739}
1740
Mike Reed42e8c532017-01-23 14:09:13 -05001741SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001742 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001743}
1744
reed@android.com8a1c16f2008-12-17 15:59:43 +00001745const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001746 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001747}
1748
Brian Osman11052242016-10-27 14:47:55 -04001749GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001750 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001751 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001752}
1753
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001754GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001755 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001756 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001757}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001758
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001759void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1760 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001761 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001762 if (outer.isEmpty()) {
1763 return;
1764 }
1765 if (inner.isEmpty()) {
1766 this->drawRRect(outer, paint);
1767 return;
1768 }
1769
1770 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001771 // be able to return ...
1772 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001773 //
1774 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001775 if (!outer.getBounds().contains(inner.getBounds())) {
1776 return;
1777 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001778
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
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003129static bool supported_for_raster_canvas(const SkImageInfo& info) {
3130 switch (info.alphaType()) {
3131 case kPremul_SkAlphaType:
3132 case kOpaque_SkAlphaType:
3133 break;
3134 default:
3135 return false;
3136 }
3137
3138 switch (info.colorType()) {
3139 case kAlpha_8_SkColorType:
3140 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003141 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003142 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003143 break;
3144 default:
3145 return false;
3146 }
3147
3148 return true;
3149}
3150
Mike Reed5df49342016-11-12 08:06:55 -06003151std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3152 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003153 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003154 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003155 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003156
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003157 SkBitmap bitmap;
3158 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003159 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003160 }
Mike Reed5df49342016-11-12 08:06:55 -06003161 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003162}
reedd5fa1a42014-08-09 11:08:05 -07003163
3164///////////////////////////////////////////////////////////////////////////////
3165
3166SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003167 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003168 : fCanvas(canvas)
3169 , fSaveCount(canvas->getSaveCount())
3170{
bsalomon49f085d2014-09-05 13:34:00 -07003171 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003172 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003173 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003174 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003175 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003176 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003177 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003178 canvas->save();
3179 }
mtklein6cfa73a2014-08-13 13:33:49 -07003180
bsalomon49f085d2014-09-05 13:34:00 -07003181 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003182 canvas->concat(*matrix);
3183 }
3184}
3185
3186SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3187 fCanvas->restoreToCount(fSaveCount);
3188}
reede8f30622016-03-23 18:59:25 -07003189
Florin Malitaee424ac2016-12-01 12:47:59 -05003190///////////////////////////////////////////////////////////////////////////////
3191
3192SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3193 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3194
Florin Malita439ace92016-12-02 12:05:41 -05003195SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3196 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3197
Florin Malitaee424ac2016-12-01 12:47:59 -05003198SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3199 (void)this->INHERITED::getSaveLayerStrategy(rec);
3200 return kNoLayer_SaveLayerStrategy;
3201}
3202
3203///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003204
reed73603f32016-09-20 08:42:38 -07003205static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3206static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3207static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3208static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3209static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3210static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003211
3212///////////////////////////////////////////////////////////////////////////////////////////////////
3213
3214SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3215 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3216 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3217 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3218 SkIPoint origin = dev->getOrigin();
3219 SkMatrix ctm = this->getTotalMatrix();
3220 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3221
3222 SkIRect clip = fMCRec->fRasterClip.getBounds();
3223 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003224 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003225 clip.setEmpty();
3226 }
3227
3228 fAllocator->updateHandle(handle, ctm, clip);
3229 return handle;
3230 }
3231 return nullptr;
3232}
3233
3234static bool install(SkBitmap* bm, const SkImageInfo& info,
3235 const SkRasterHandleAllocator::Rec& rec) {
3236 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3237 rec.fReleaseProc, rec.fReleaseCtx);
3238}
3239
3240SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3241 SkBitmap* bm) {
3242 SkRasterHandleAllocator::Rec rec;
3243 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3244 return nullptr;
3245 }
3246 return rec.fHandle;
3247}
3248
3249std::unique_ptr<SkCanvas>
3250SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3251 const SkImageInfo& info, const Rec* rec) {
3252 if (!alloc || !supported_for_raster_canvas(info)) {
3253 return nullptr;
3254 }
3255
3256 SkBitmap bm;
3257 Handle hndl;
3258
3259 if (rec) {
3260 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3261 } else {
3262 hndl = alloc->allocBitmap(info, &bm);
3263 }
3264 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3265}