blob: 76b4a522b27a61187d771035181c35ae8f5c7d8f [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 {
Florin Malita713b8ef2017-04-28 10:57:24 -0400250 DeviceCM* fNext;
251 sk_sp<SkBaseDevice> fDevice;
252 SkRasterClip fClip;
253 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
254 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255
Florin Malita713b8ef2017-04-28 10:57:24 -0400256 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700257 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400258 , fDevice(std::move(device))
259 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700260 , fStashedMatrix(stashed)
Florin Malita713b8ef2017-04-28 10:57:24 -0400261 {}
reed@google.com4b226022011-01-11 18:32:13 +0000262
mtkleinfeaadee2015-04-08 11:25:48 -0700263 void reset(const SkIRect& bounds) {
264 SkASSERT(!fPaint);
265 SkASSERT(!fNext);
266 SkASSERT(fDevice);
267 fClip.setRect(bounds);
268 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000269};
270
271/* This is the record we keep for each save/restore level in the stack.
272 Since a level optionally copies the matrix and/or stack, we have pointers
273 for these fields. If the value is copied for this level, the copy is
274 stored in the ...Storage field, and the pointer points to that. If the
275 value is not copied for this level, we ignore ...Storage, and just point
276 at the corresponding value in the previous level in the stack.
277*/
278class SkCanvas::MCRec {
279public:
reed1f836ee2014-07-07 07:49:34 -0700280 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700281 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282 /* If there are any layers in the stack, this points to the top-most
283 one that is at or below this level in the stack (so we know what
284 bitmap/device to draw into from this level. This value is NOT
285 reference counted, since the real owner is either our fLayer field,
286 or a previous one in a lower level.)
287 */
Mike Reeda1361362017-03-07 09:37:29 -0500288 DeviceCM* fTopLayer;
289 SkConservativeClip fRasterClip;
290 SkMatrix fMatrix;
291 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292
vjiaoblacke5de1302016-07-13 14:05:28 -0700293 // This is the current cumulative depth (aggregate of all done translateZ calls)
294 SkScalar fCurDrawDepth;
295
Mike Reeda1361362017-03-07 09:37:29 -0500296 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700297 fFilter = nullptr;
298 fLayer = nullptr;
299 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800300 fMatrix.reset();
301 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700302 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700303
reedd9544982014-09-09 18:46:22 -0700304 // don't bother initializing fNext
305 inc_rec();
306 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700307 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
308 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700309 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700310 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700311 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800312 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700313
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 // don't bother initializing fNext
315 inc_rec();
316 }
317 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000318 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700319 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320 dec_rec();
321 }
mtkleinfeaadee2015-04-08 11:25:48 -0700322
323 void reset(const SkIRect& bounds) {
324 SkASSERT(fLayer);
325 SkASSERT(fDeferredSaveCount == 0);
326
327 fMatrix.reset();
328 fRasterClip.setRect(bounds);
329 fLayer->reset(bounds);
330 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331};
332
Mike Reeda1361362017-03-07 09:37:29 -0500333class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334public:
Mike Reeda1361362017-03-07 09:37:29 -0500335 SkDrawIter(SkCanvas* canvas)
336 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
337 {}
reed@google.com4b226022011-01-11 18:32:13 +0000338
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000340 const DeviceCM* rec = fCurrLayer;
341 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400342 fDevice = rec->fDevice.get();
343 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700345 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346 return true;
347 }
348 return false;
349 }
reed@google.com4b226022011-01-11 18:32:13 +0000350
reed@google.com6f8f2922011-03-04 22:27:10 +0000351 int getX() const { return fDevice->getOrigin().x(); }
352 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000354
Mike Reed99330ba2017-02-22 11:01:08 -0500355 SkBaseDevice* fDevice;
356
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 const DeviceCM* fCurrLayer;
359 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360};
361
Florin Malita713b8ef2017-04-28 10:57:24 -0400362#define FOR_EACH_TOP_DEVICE( code ) \
363 do { \
364 DeviceCM* layer = fMCRec->fTopLayer; \
365 while (layer) { \
366 SkBaseDevice* device = layer->fDevice.get(); \
367 if (device) { \
368 code; \
369 } \
370 layer = layer->fNext; \
371 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500372 } while (0)
373
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374/////////////////////////////////////////////////////////////////////////////
375
reeddbc3cef2015-04-29 12:18:57 -0700376static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
377 return lazy->isValid() ? lazy->get() : lazy->set(orig);
378}
379
380/**
381 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700382 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700383 */
reedd053ce92016-03-22 10:17:23 -0700384static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700385 SkImageFilter* imgf = paint.getImageFilter();
386 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700387 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700388 }
389
reedd053ce92016-03-22 10:17:23 -0700390 SkColorFilter* imgCFPtr;
391 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700392 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700393 }
reedd053ce92016-03-22 10:17:23 -0700394 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700395
396 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700397 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700398 // there is no existing paint colorfilter, so we can just return the imagefilter's
399 return imgCF;
400 }
401
402 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
403 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700404 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700405}
406
senorblanco87e066e2015-10-28 11:23:36 -0700407/**
408 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
409 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
410 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
411 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
412 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
413 * conservative "effective" bounds based on the settings in the paint... with one exception. This
414 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
415 * deliberately ignored.
416 */
417static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
418 const SkRect& rawBounds,
419 SkRect* storage) {
420 SkPaint tmpUnfiltered(paint);
421 tmpUnfiltered.setImageFilter(nullptr);
422 if (tmpUnfiltered.canComputeFastBounds()) {
423 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
424 } else {
425 return rawBounds;
426 }
427}
428
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429class AutoDrawLooper {
430public:
senorblanco87e066e2015-10-28 11:23:36 -0700431 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
432 // paint. It's used to determine the size of the offscreen layer for filters.
433 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700434 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700435 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000436 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800437#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800439#else
440 fFilter = nullptr;
441#endif
reed4a8126e2014-09-22 07:29:03 -0700442 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000443 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700444 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000445 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446
reedd053ce92016-03-22 10:17:23 -0700447 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700448 if (simplifiedCF) {
449 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700450 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700451 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700452 fPaint = paint;
453 }
454
455 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700456 /**
457 * We implement ImageFilters for a given draw by creating a layer, then applying the
458 * imagefilter to the pixels of that layer (its backing surface/image), and then
459 * we call restore() to xfer that layer to the main canvas.
460 *
461 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
462 * 2. Generate the src pixels:
463 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
464 * return (fPaint). We then draw the primitive (using srcover) into a cleared
465 * buffer/surface.
466 * 3. Restore the layer created in #1
467 * The imagefilter is passed the buffer/surface from the layer (now filled with the
468 * src pixels of the primitive). It returns a new "filtered" buffer, which we
469 * draw onto the previous layer using the xfermode from the original paint.
470 */
reed@google.com8926b162012-03-23 15:36:36 +0000471 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500472 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700473 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700474 SkRect storage;
475 if (rawBounds) {
476 // Make rawBounds include all paint outsets except for those due to image filters.
477 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
478 }
reedbfd5f172016-01-07 11:28:08 -0800479 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700480 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700481 fTempLayerForImageFilter = true;
482 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000483 }
484
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000485 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500486 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000487 fIsSimple = false;
488 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700489 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000490 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700491 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000492 }
493 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000494
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700496 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000497 fCanvas->internalRestore();
498 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000499 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000500 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000501
reed@google.com4e2b3d32011-04-07 14:18:59 +0000502 const SkPaint& paint() const {
503 SkASSERT(fPaint);
504 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000505 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000506
reed@google.com129ec222012-05-15 13:24:09 +0000507 bool next(SkDrawFilter::Type drawType) {
508 if (fDone) {
509 return false;
510 } else if (fIsSimple) {
511 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000512 return !fPaint->nothingToDraw();
513 } else {
514 return this->doNext(drawType);
515 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000516 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000517
reed@android.com8a1c16f2008-12-17 15:59:43 +0000518private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500519 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700520 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000521 SkCanvas* fCanvas;
522 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000523 SkDrawFilter* fFilter;
524 const SkPaint* fPaint;
525 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700526 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000527 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000528 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000529 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500530 char fStorage[48];
531 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000532
533 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534};
535
reed@google.com129ec222012-05-15 13:24:09 +0000536bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700537 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000538 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700539 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000540
reeddbc3cef2015-04-29 12:18:57 -0700541 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
542 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000543
reed5c476fb2015-04-20 08:04:21 -0700544 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700545 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700546 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000547 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000548
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000549 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000550 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000551 return false;
552 }
553 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000554 if (!fFilter->filter(paint, drawType)) {
555 fDone = true;
556 return false;
557 }
halcanary96fcdcc2015-08-27 07:41:13 -0700558 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000559 // no looper means we only draw once
560 fDone = true;
561 }
562 }
563 fPaint = paint;
564
565 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000566 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000567 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000568 }
569
570 // call this after any possible paint modifiers
571 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700572 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000573 return false;
574 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000575 return true;
576}
577
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578////////// macros to place around the internal draw calls //////////////////
579
reed3aafe112016-08-18 12:45:34 -0700580#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
581 this->predrawNotify(); \
582 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
583 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800584 SkDrawIter iter(this);
585
586
reed@google.com8926b162012-03-23 15:36:36 +0000587#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000588 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700589 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000590 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000591 SkDrawIter iter(this);
592
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000593#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000594 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700595 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000596 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000598
reedc83a2972015-07-16 07:40:45 -0700599#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
600 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700601 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700602 while (looper.next(type)) { \
603 SkDrawIter iter(this);
604
reed@google.com4e2b3d32011-04-07 14:18:59 +0000605#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606
607////////////////////////////////////////////////////////////////////////////
608
msarettfbfa2582016-08-12 08:29:08 -0700609static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
610 if (bounds.isEmpty()) {
611 return SkRect::MakeEmpty();
612 }
613
614 // Expand bounds out by 1 in case we are anti-aliasing. We store the
615 // bounds as floats to enable a faster quick reject implementation.
616 SkRect dst;
617 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
618 return dst;
619}
620
mtkleinfeaadee2015-04-08 11:25:48 -0700621void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
622 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700623 fMCRec->reset(bounds);
624
625 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500626 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400627 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700628 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700629 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700630}
631
reedd9544982014-09-09 18:46:22 -0700632SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800633 if (device && device->forceConservativeRasterClip()) {
634 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
635 }
reed42b73eb2015-11-20 13:42:42 -0800636
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000637 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800638 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700639 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700640#ifdef SK_EXPERIMENTAL_SHADOWING
641 fLights = nullptr;
642#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643
644 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500645 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500646 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700647 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648
reeda499f902015-05-01 09:34:31 -0700649 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
650 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita713b8ef2017-04-28 10:57:24 -0400651 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700652
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654
halcanary96fcdcc2015-08-27 07:41:13 -0700655 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000656
reedf92c8662014-08-18 08:02:43 -0700657 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700658 // The root device and the canvas should always have the same pixel geometry
659 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800660 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700661 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500662
Mike Reedc42a1cd2017-02-14 14:25:14 -0500663 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700664 }
msarettfbfa2582016-08-12 08:29:08 -0700665
reedf92c8662014-08-18 08:02:43 -0700666 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667}
668
reed@google.comcde92112011-07-06 20:00:52 +0000669SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000670 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700671 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000672{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000673 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000674
halcanary96fcdcc2015-08-27 07:41:13 -0700675 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000676}
677
reed96a857e2015-01-25 10:33:58 -0800678SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000679 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800680 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000681{
682 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700683
Mike Reed566e53c2017-03-10 10:49:45 -0500684 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700685 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700686}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000687
reed78e27682014-11-19 08:04:34 -0800688SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700689 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700690 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700691{
692 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700693
Mike Reed566e53c2017-03-10 10:49:45 -0500694 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
695 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700696}
697
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000698SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000699 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700700 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000701{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000702 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700703
reedd9544982014-09-09 18:46:22 -0700704 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000705}
706
robertphillipsfcf78292015-06-19 11:49:52 -0700707SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
708 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700709 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700710{
711 inc_canvas();
712
713 this->init(device, flags);
714}
715
reed4a8126e2014-09-22 07:29:03 -0700716SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700717 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700718 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700719{
720 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700721
Hal Canary704cd322016-11-07 14:13:52 -0500722 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
723 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700724}
reed29c857d2014-09-21 10:25:07 -0700725
Mike Reed356f7c22017-01-10 11:58:39 -0500726SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
727 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700728 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
729 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500730 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700731{
732 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700733
Mike Reed356f7c22017-01-10 11:58:39 -0500734 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500735 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000736}
737
Mike Reed356f7c22017-01-10 11:58:39 -0500738SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
739
Matt Sarett31f99ce2017-04-11 08:46:01 -0400740#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
741SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
742 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
743 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
744 , fAllocator(nullptr)
745{
746 inc_canvas();
747
748 SkBitmap tmp(bitmap);
749 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
750 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
751 this->init(device.get(), kDefault_InitFlags);
752}
753#endif
754
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755SkCanvas::~SkCanvas() {
756 // free up the contents of our deque
757 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000758
reed@android.com8a1c16f2008-12-17 15:59:43 +0000759 this->internalRestore(); // restore the last, since we're going away
760
halcanary385fe4d2015-08-26 13:07:48 -0700761 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000762
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763 dec_canvas();
764}
765
fmalita53d9f1c2016-01-25 06:23:54 -0800766#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767SkDrawFilter* SkCanvas::getDrawFilter() const {
768 return fMCRec->fFilter;
769}
770
771SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700772 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
774 return filter;
775}
fmalita77650002016-01-21 18:47:11 -0800776#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000778SkMetaData& SkCanvas::getMetaData() {
779 // metadata users are rare, so we lazily allocate it. If that changes we
780 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700781 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000782 fMetaData = new SkMetaData;
783 }
784 return *fMetaData;
785}
786
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787///////////////////////////////////////////////////////////////////////////////
788
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000789void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700790 this->onFlush();
791}
792
793void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000794 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000795 if (device) {
796 device->flush();
797 }
798}
799
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000800SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000801 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000802 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
803}
804
senorblancoafc7cce2016-02-02 18:44:15 -0800805SkIRect SkCanvas::getTopLayerBounds() const {
806 SkBaseDevice* d = this->getTopDevice();
807 if (!d) {
808 return SkIRect::MakeEmpty();
809 }
810 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
811}
812
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000813SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000814 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000815 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000816 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400817 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818}
819
Florin Malita0ed3b642017-01-13 16:56:38 +0000820SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400821 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000822}
823
reed96472de2014-12-10 09:53:42 -0800824bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000825 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000826 if (!device) {
827 return false;
828 }
mtkleinf0f14112014-12-12 08:46:25 -0800829
Matt Sarett03dd6d52017-01-23 12:15:09 -0500830 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000831}
832
Mike Reed12e946b2017-04-17 10:53:29 -0400833bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
834 return pm.addr() && this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y);
835}
836
837bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
838 SkPixmap pm;
839 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
840}
841
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000842bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400843 SkPixmap pm;
844 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700845 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000846 }
847 return false;
848}
849
Matt Sarett03dd6d52017-01-23 12:15:09 -0500850bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000851 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000852 SkBaseDevice* device = this->getDevice();
853 if (!device) {
854 return false;
855 }
856
Matt Sarett03dd6d52017-01-23 12:15:09 -0500857 // This check gives us an early out and prevents generation ID churn on the surface.
858 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
859 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
860 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
861 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000862 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000863
Matt Sarett03dd6d52017-01-23 12:15:09 -0500864 // Tell our owning surface to bump its generation ID.
865 const bool completeOverwrite =
866 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700867 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700868
Matt Sarett03dd6d52017-01-23 12:15:09 -0500869 // This can still fail, most notably in the case of a invalid color type or alpha type
870 // conversion. We could pull those checks into this function and avoid the unnecessary
871 // generation ID bump. But then we would be performing those checks twice, since they
872 // are also necessary at the bitmap/pixmap entry points.
873 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000874}
reed@google.com51df9e32010-12-23 19:29:18 +0000875
reed@android.com8a1c16f2008-12-17 15:59:43 +0000876//////////////////////////////////////////////////////////////////////////////
877
reed2ff1fce2014-12-11 07:07:37 -0800878void SkCanvas::checkForDeferredSave() {
879 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800880 this->doSave();
881 }
882}
883
reedf0090cb2014-11-26 08:55:51 -0800884int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800885#ifdef SK_DEBUG
886 int count = 0;
887 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
888 for (;;) {
889 const MCRec* rec = (const MCRec*)iter.next();
890 if (!rec) {
891 break;
892 }
893 count += 1 + rec->fDeferredSaveCount;
894 }
895 SkASSERT(count == fSaveCount);
896#endif
897 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800898}
899
900int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800901 fSaveCount += 1;
902 fMCRec->fDeferredSaveCount += 1;
903 return this->getSaveCount() - 1; // return our prev value
904}
905
906void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800907 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700908
909 SkASSERT(fMCRec->fDeferredSaveCount > 0);
910 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800911 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800912}
913
914void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800915 if (fMCRec->fDeferredSaveCount > 0) {
916 SkASSERT(fSaveCount > 1);
917 fSaveCount -= 1;
918 fMCRec->fDeferredSaveCount -= 1;
919 } else {
920 // check for underflow
921 if (fMCStack.count() > 1) {
922 this->willRestore();
923 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700924 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800925 this->internalRestore();
926 this->didRestore();
927 }
reedf0090cb2014-11-26 08:55:51 -0800928 }
929}
930
931void SkCanvas::restoreToCount(int count) {
932 // sanity check
933 if (count < 1) {
934 count = 1;
935 }
mtkleinf0f14112014-12-12 08:46:25 -0800936
reedf0090cb2014-11-26 08:55:51 -0800937 int n = this->getSaveCount() - count;
938 for (int i = 0; i < n; ++i) {
939 this->restore();
940 }
941}
942
reed2ff1fce2014-12-11 07:07:37 -0800943void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700945 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000946 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000947
Mike Reedc42a1cd2017-02-14 14:25:14 -0500948 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949}
950
reed4960eee2015-12-18 07:09:18 -0800951bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800952 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000953}
954
reed4960eee2015-12-18 07:09:18 -0800955bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700956 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500957 SkIRect clipBounds = this->getDeviceClipBounds();
958 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000959 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000960 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000961
reed96e657d2015-03-10 17:30:07 -0700962 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
963
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000964 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700965 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800966 if (bounds && !imageFilter->canComputeFastBounds()) {
967 bounds = nullptr;
968 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000969 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000970 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700971 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000972 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000973
reed96e657d2015-03-10 17:30:07 -0700974 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000975 r.roundOut(&ir);
976 // early exit if the layer's bounds are clipped out
977 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800978 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500979 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700980 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700981 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000982 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000983 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984 }
985 } else { // no user bounds, so just use the clip
986 ir = clipBounds;
987 }
reed180aec42015-03-11 10:39:04 -0700988 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989
reed4960eee2015-12-18 07:09:18 -0800990 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700991 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700992 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700993 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000994 }
995
996 if (intersection) {
997 *intersection = ir;
998 }
999 return true;
1000}
1001
reed4960eee2015-12-18 07:09:18 -08001002
reed4960eee2015-12-18 07:09:18 -08001003int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1004 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001005}
1006
reed70ee31b2015-12-10 13:44:45 -08001007int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001008 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1009}
1010
1011int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1012 SaveLayerRec rec(origRec);
1013 if (gIgnoreSaveLayerBounds) {
1014 rec.fBounds = nullptr;
1015 }
1016 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1017 fSaveCount += 1;
1018 this->internalSaveLayer(rec, strategy);
1019 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001020}
1021
reeda2217ef2016-07-20 06:04:34 -07001022void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001023 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001024 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001025 SkDraw draw;
1026 SkRasterClip rc;
1027 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1028 if (!dst->accessPixels(&draw.fDst)) {
1029 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001030 }
reeda2217ef2016-07-20 06:04:34 -07001031 draw.fMatrix = &SkMatrix::I();
1032 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001033
1034 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001035 if (filter) {
1036 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1037 }
reeda2217ef2016-07-20 06:04:34 -07001038
Mike Reedc42a1cd2017-02-14 14:25:14 -05001039 int x = src->getOrigin().x() - dstOrigin.x();
1040 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001041 auto special = src->snapSpecial();
1042 if (special) {
Mike Reeda1361362017-03-07 09:37:29 -05001043 dst->drawSpecial(special.get(), x, y, p);
reeda2217ef2016-07-20 06:04:34 -07001044 }
robertphillips7354a4b2015-12-16 05:08:27 -08001045}
reed70ee31b2015-12-10 13:44:45 -08001046
reed129ed1c2016-02-22 06:42:31 -08001047static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1048 const SkPaint* paint) {
1049 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1050 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001051 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001052 const bool hasImageFilter = paint && paint->getImageFilter();
1053
1054 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1055 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1056 // force to L32
1057 return SkImageInfo::MakeN32(w, h, alphaType);
1058 } else {
1059 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001060 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001061 }
1062}
1063
reed4960eee2015-12-18 07:09:18 -08001064void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1065 const SkRect* bounds = rec.fBounds;
1066 const SkPaint* paint = rec.fPaint;
1067 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1068
reed8c30a812016-04-20 16:36:51 -07001069 SkLazyPaint lazyP;
1070 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1071 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001072 SkMatrix remainder;
1073 SkSize scale;
1074 /*
1075 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1076 * but they do handle scaling. To accommodate this, we do the following:
1077 *
1078 * 1. Stash off the current CTM
1079 * 2. Decompose the CTM into SCALE and REMAINDER
1080 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1081 * contains the REMAINDER
1082 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1083 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1084 * of the original imagefilter, and draw that (via drawSprite)
1085 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1086 *
1087 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1088 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1089 */
reed96a04f32016-04-25 09:25:15 -07001090 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001091 stashedMatrix.decomposeScale(&scale, &remainder))
1092 {
1093 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1094 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1095 SkPaint* p = lazyP.set(*paint);
1096 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1097 SkFilterQuality::kLow_SkFilterQuality,
1098 sk_ref_sp(imageFilter)));
1099 imageFilter = p->getImageFilter();
1100 paint = p;
1101 }
reed8c30a812016-04-20 16:36:51 -07001102
junov@chromium.orga907ac32012-02-24 21:54:07 +00001103 // do this before we create the layer. We don't call the public save() since
1104 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001105 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001106
junov@chromium.orga907ac32012-02-24 21:54:07 +00001107 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001108 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001109 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110 }
1111
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001112 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1113 // the clipRectBounds() call above?
1114 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001115 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001116 }
1117
reed4960eee2015-12-18 07:09:18 -08001118 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001119 SkPixelGeometry geo = fProps.pixelGeometry();
1120 if (paint) {
reed76033be2015-03-14 10:54:31 -07001121 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001122 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001123 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001124 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001125 }
1126 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001127
robertphillips5139e502016-07-19 05:10:40 -07001128 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001129 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001130 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001131 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001132 }
reedb2db8982014-11-13 12:41:02 -08001133
robertphillips5139e502016-07-19 05:10:40 -07001134 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001135 paint);
1136
Hal Canary704cd322016-11-07 14:13:52 -05001137 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001138 {
reed70ee31b2015-12-10 13:44:45 -08001139 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001140 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001141 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001142 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001143 preserveLCDText,
1144 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001145 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1146 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001147 return;
reed61f501f2015-04-29 08:34:00 -07001148 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001149 }
Florin Malita713b8ef2017-04-28 10:57:24 -04001150 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151
Mike Reedb43a3e02017-02-11 10:18:58 -05001152 // only have a "next" if this new layer doesn't affect the clip (rare)
1153 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001154 fMCRec->fLayer = layer;
1155 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001156
Mike Reedc61abee2017-02-28 17:45:27 -05001157 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001158 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001159 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001160 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001161
Mike Reedc42a1cd2017-02-14 14:25:14 -05001162 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1163
1164 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1165 if (layer->fNext) {
1166 // need to punch a hole in the previous device, so we don't draw there, given that
1167 // the new top-layer will allow drawing to happen "below" it.
1168 SkRegion hole(ir);
1169 do {
1170 layer = layer->fNext;
1171 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1172 } while (layer->fNext);
1173 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001174}
1175
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001176int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001177 if (0xFF == alpha) {
1178 return this->saveLayer(bounds, nullptr);
1179 } else {
1180 SkPaint tmpPaint;
1181 tmpPaint.setAlpha(alpha);
1182 return this->saveLayer(bounds, &tmpPaint);
1183 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001184}
1185
reed@android.com8a1c16f2008-12-17 15:59:43 +00001186void SkCanvas::internalRestore() {
1187 SkASSERT(fMCStack.count() != 0);
1188
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001189 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001190 DeviceCM* layer = fMCRec->fLayer; // may be null
1191 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001192 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001193
1194 // now do the normal restore()
1195 fMCRec->~MCRec(); // balanced in save()
1196 fMCStack.pop_back();
1197 fMCRec = (MCRec*)fMCStack.back();
1198
Mike Reedc42a1cd2017-02-14 14:25:14 -05001199 if (fMCRec) {
1200 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1201 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001202
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1204 since if we're being recorded, we don't want to record this (the
1205 recorder will have already recorded the restore).
1206 */
bsalomon49f085d2014-09-05 13:34:00 -07001207 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001208 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001209 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001210 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
1211 layer->fPaint.get());
reed8c30a812016-04-20 16:36:51 -07001212 // restore what we smashed in internalSaveLayer
1213 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001214 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001215 delete layer;
reedb679ca82015-04-07 04:40:48 -07001216 } else {
1217 // we're at the root
reeda499f902015-05-01 09:34:31 -07001218 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001219 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001220 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001222 }
msarettfbfa2582016-08-12 08:29:08 -07001223
1224 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001225 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001226 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1227 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228}
1229
reede8f30622016-03-23 18:59:25 -07001230sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001231 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001232 props = &fProps;
1233 }
1234 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001235}
1236
reede8f30622016-03-23 18:59:25 -07001237sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001238 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001239 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001240}
1241
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001242SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001243 return this->onImageInfo();
1244}
1245
1246SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001247 SkBaseDevice* dev = this->getDevice();
1248 if (dev) {
1249 return dev->imageInfo();
1250 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001251 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001252 }
1253}
1254
brianosman898235c2016-04-06 07:38:23 -07001255bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001256 return this->onGetProps(props);
1257}
1258
1259bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001260 SkBaseDevice* dev = this->getDevice();
1261 if (dev) {
1262 if (props) {
1263 *props = fProps;
1264 }
1265 return true;
1266 } else {
1267 return false;
1268 }
1269}
1270
reed6ceeebd2016-03-09 14:26:26 -08001271bool SkCanvas::peekPixels(SkPixmap* pmap) {
1272 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001273}
1274
reed884e97c2015-05-26 11:31:54 -07001275bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001276 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001277 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001278}
1279
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001280void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001281 SkPixmap pmap;
1282 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001283 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001284 }
1285 if (info) {
1286 *info = pmap.info();
1287 }
1288 if (rowBytes) {
1289 *rowBytes = pmap.rowBytes();
1290 }
1291 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001292 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001293 }
reed884e97c2015-05-26 11:31:54 -07001294 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001295}
1296
reed884e97c2015-05-26 11:31:54 -07001297bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001298 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001299 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001300}
1301
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303
reed7503d602016-07-15 14:23:29 -07001304void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001306 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307 paint = &tmp;
1308 }
reed@google.com4b226022011-01-11 18:32:13 +00001309
reed@google.com8926b162012-03-23 15:36:36 +00001310 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001311
reed@android.com8a1c16f2008-12-17 15:59:43 +00001312 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001313 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001314 paint = &looper.paint();
1315 SkImageFilter* filter = paint->getImageFilter();
1316 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001317 if (filter) {
1318 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1319 if (specialImage) {
Mike Reeda1361362017-03-07 09:37:29 -05001320 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint);
Robert Phillips833dcf42016-11-18 08:44:13 -05001321 }
reed@google.com76dd2772012-01-05 21:15:07 +00001322 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001323 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001324 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325 }
reeda2217ef2016-07-20 06:04:34 -07001326
reed@google.com4e2b3d32011-04-07 14:18:59 +00001327 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328}
1329
reed32704672015-12-16 08:27:10 -08001330/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001331
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001332void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001333 if (dx || dy) {
1334 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001335 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001336
reedfe69b502016-09-12 06:31:48 -07001337 // Translate shouldn't affect the is-scale-translateness of the matrix.
1338 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001339
Mike Reedc42a1cd2017-02-14 14:25:14 -05001340 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001341
reedfe69b502016-09-12 06:31:48 -07001342 this->didTranslate(dx,dy);
1343 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344}
1345
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001346void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001347 SkMatrix m;
1348 m.setScale(sx, sy);
1349 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350}
1351
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001352void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001353 SkMatrix m;
1354 m.setRotate(degrees);
1355 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356}
1357
bungeman7438bfc2016-07-12 15:01:19 -07001358void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1359 SkMatrix m;
1360 m.setRotate(degrees, px, py);
1361 this->concat(m);
1362}
1363
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001364void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001365 SkMatrix m;
1366 m.setSkew(sx, sy);
1367 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001368}
1369
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001370void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001371 if (matrix.isIdentity()) {
1372 return;
1373 }
1374
reed2ff1fce2014-12-11 07:07:37 -08001375 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001376 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001377 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001378
Mike Reed7627fa52017-02-08 10:07:53 -05001379 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001380
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001381 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001382}
1383
reed8c30a812016-04-20 16:36:51 -07001384void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001385 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001386 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001387
Mike Reedc42a1cd2017-02-14 14:25:14 -05001388 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001389}
1390
1391void SkCanvas::setMatrix(const SkMatrix& matrix) {
1392 this->checkForDeferredSave();
1393 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001394 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001395}
1396
reed@android.com8a1c16f2008-12-17 15:59:43 +00001397void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001398 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001399}
1400
vjiaoblack95302da2016-07-21 10:25:54 -07001401#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001402void SkCanvas::translateZ(SkScalar z) {
1403 this->checkForDeferredSave();
1404 this->fMCRec->fCurDrawDepth += z;
1405 this->didTranslateZ(z);
1406}
1407
1408SkScalar SkCanvas::getZ() const {
1409 return this->fMCRec->fCurDrawDepth;
1410}
1411
vjiaoblack95302da2016-07-21 10:25:54 -07001412void SkCanvas::setLights(sk_sp<SkLights> lights) {
1413 this->fLights = lights;
1414}
1415
1416sk_sp<SkLights> SkCanvas::getLights() const {
1417 return this->fLights;
1418}
1419#endif
1420
reed@android.com8a1c16f2008-12-17 15:59:43 +00001421//////////////////////////////////////////////////////////////////////////////
1422
Mike Reedc1f77742016-12-09 09:00:50 -05001423void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001424 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001425 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1426 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001427}
1428
Mike Reedc1f77742016-12-09 09:00:50 -05001429void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001430 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001431
Mike Reed7627fa52017-02-08 10:07:53 -05001432 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001433
reedc64eff52015-11-21 12:39:45 -08001434 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001435 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1436 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001437 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438}
1439
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001440void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1441 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001442 if (fClipRestrictionRect.isEmpty()) {
1443 // we notify the device, but we *dont* resolve deferred saves (since we're just
1444 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001445 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001446 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001447 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001448 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001449 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001450 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001451 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1452 }
1453}
1454
Mike Reedc1f77742016-12-09 09:00:50 -05001455void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001456 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001457 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001458 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001459 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1460 } else {
1461 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001462 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001463}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001464
Mike Reedc1f77742016-12-09 09:00:50 -05001465void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001466 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001467
Brian Salomona3b45d42016-10-03 11:36:16 -04001468 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001469
Mike Reed7627fa52017-02-08 10:07:53 -05001470 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001471
Brian Salomona3b45d42016-10-03 11:36:16 -04001472 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1473 isAA);
1474 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001475}
1476
Mike Reedc1f77742016-12-09 09:00:50 -05001477void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001478 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001479 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001480
1481 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1482 SkRect r;
1483 if (path.isRect(&r)) {
1484 this->onClipRect(r, op, edgeStyle);
1485 return;
1486 }
1487 SkRRect rrect;
1488 if (path.isOval(&r)) {
1489 rrect.setOval(r);
1490 this->onClipRRect(rrect, op, edgeStyle);
1491 return;
1492 }
1493 if (path.isRRect(&rrect)) {
1494 this->onClipRRect(rrect, op, edgeStyle);
1495 return;
1496 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001497 }
robertphillips39f05382015-11-24 09:30:12 -08001498
1499 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001500}
1501
Mike Reedc1f77742016-12-09 09:00:50 -05001502void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001503 AutoValidateClip avc(this);
1504
Brian Salomona3b45d42016-10-03 11:36:16 -04001505 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001506
Mike Reed7627fa52017-02-08 10:07:53 -05001507 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508
Brian Salomona3b45d42016-10-03 11:36:16 -04001509 const SkPath* rasterClipPath = &path;
1510 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001511 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1512 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001513 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001514}
1515
Mike Reedc1f77742016-12-09 09:00:50 -05001516void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001517 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001518 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001519}
1520
Mike Reedc1f77742016-12-09 09:00:50 -05001521void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001522 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001523
reed@google.com5c3d1472011-02-22 19:12:23 +00001524 AutoValidateClip avc(this);
1525
reed73603f32016-09-20 08:42:38 -07001526 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001527 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001528}
1529
reed@google.com819c9212011-02-23 18:56:55 +00001530#ifdef SK_DEBUG
1531void SkCanvas::validateClip() const {
1532 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001533 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001534 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001535 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001536 return;
1537 }
reed@google.com819c9212011-02-23 18:56:55 +00001538}
1539#endif
1540
Mike Reeda1361362017-03-07 09:37:29 -05001541bool SkCanvas::androidFramework_isClipAA() const {
1542 bool containsAA = false;
1543
1544 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1545
1546 return containsAA;
1547}
1548
1549class RgnAccumulator {
1550 SkRegion* fRgn;
1551public:
1552 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1553 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1554 SkIPoint origin = device->getOrigin();
1555 if (origin.x() | origin.y()) {
1556 rgn->translate(origin.x(), origin.y());
1557 }
1558 fRgn->op(*rgn, SkRegion::kUnion_Op);
1559 }
1560};
1561
1562void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1563 RgnAccumulator accum(rgn);
1564 SkRegion tmp;
1565
1566 rgn->setEmpty();
1567 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001568}
1569
reed@google.com5c3d1472011-02-22 19:12:23 +00001570///////////////////////////////////////////////////////////////////////////////
1571
reed@google.com754de5f2014-02-24 19:38:20 +00001572bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001573 return fMCRec->fRasterClip.isEmpty();
1574
1575 // TODO: should we only use the conservative answer in a recording canvas?
1576#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001577 SkBaseDevice* dev = this->getTopDevice();
1578 // if no device we return true
1579 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001580#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001581}
1582
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001583bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001584 SkBaseDevice* dev = this->getTopDevice();
1585 // if no device we return false
1586 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001587}
1588
msarettfbfa2582016-08-12 08:29:08 -07001589static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1590#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1591 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1592 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1593 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1594 return 0xF != _mm_movemask_ps(mask);
1595#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1596 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1597 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1598 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1599 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1600#else
1601 SkRect devRectAsRect;
1602 SkRect devClipAsRect;
1603 devRect.store(&devRectAsRect.fLeft);
1604 devClip.store(&devClipAsRect.fLeft);
1605 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1606#endif
1607}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001608
msarettfbfa2582016-08-12 08:29:08 -07001609// It's important for this function to not be inlined. Otherwise the compiler will share code
1610// between the fast path and the slow path, resulting in two slow paths.
1611static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1612 const SkMatrix& matrix) {
1613 SkRect deviceRect;
1614 matrix.mapRect(&deviceRect, src);
1615 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1616}
1617
1618bool SkCanvas::quickReject(const SkRect& src) const {
1619#ifdef SK_DEBUG
1620 // Verify that fDeviceClipBounds are set properly.
1621 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001622 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001623 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001624 } else {
msarettfbfa2582016-08-12 08:29:08 -07001625 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001626 }
msarettfbfa2582016-08-12 08:29:08 -07001627
msarett9637ea92016-08-18 14:03:30 -07001628 // Verify that fIsScaleTranslate is set properly.
1629 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001630#endif
1631
msarett9637ea92016-08-18 14:03:30 -07001632 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001633 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1634 }
1635
1636 // We inline the implementation of mapScaleTranslate() for the fast path.
1637 float sx = fMCRec->fMatrix.getScaleX();
1638 float sy = fMCRec->fMatrix.getScaleY();
1639 float tx = fMCRec->fMatrix.getTranslateX();
1640 float ty = fMCRec->fMatrix.getTranslateY();
1641 Sk4f scale(sx, sy, sx, sy);
1642 Sk4f trans(tx, ty, tx, ty);
1643
1644 // Apply matrix.
1645 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1646
1647 // Make sure left < right, top < bottom.
1648 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1649 Sk4f min = Sk4f::Min(ltrb, rblt);
1650 Sk4f max = Sk4f::Max(ltrb, rblt);
1651 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1652 // ARM this sequence generates the fastest (a single instruction).
1653 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1654
1655 // Check if the device rect is NaN or outside the clip.
1656 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657}
1658
reed@google.com3b3e8952012-08-16 20:53:31 +00001659bool SkCanvas::quickReject(const SkPath& path) const {
1660 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001661}
1662
Mike Reed42e8c532017-01-23 14:09:13 -05001663SkRect SkCanvas::onGetLocalClipBounds() const {
1664 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001665 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001666 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001667 }
1668
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001669 SkMatrix inverse;
1670 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001671 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001672 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001673 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001674
Mike Reed42e8c532017-01-23 14:09:13 -05001675 SkRect bounds;
1676 SkRect r;
1677 // adjust it outwards in case we are antialiasing
1678 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001679
Mike Reed42e8c532017-01-23 14:09:13 -05001680 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1681 ibounds.fRight + inset, ibounds.fBottom + inset);
1682 inverse.mapRect(&bounds, r);
1683 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001684}
1685
Mike Reed42e8c532017-01-23 14:09:13 -05001686SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001687 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001688}
1689
reed@android.com8a1c16f2008-12-17 15:59:43 +00001690const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001691 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692}
1693
Brian Osman11052242016-10-27 14:47:55 -04001694GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001695 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001696 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001697}
1698
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001699GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001700 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001701 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001702}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001703
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001704void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1705 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001706 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001707 if (outer.isEmpty()) {
1708 return;
1709 }
1710 if (inner.isEmpty()) {
1711 this->drawRRect(outer, paint);
1712 return;
1713 }
1714
1715 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001716 // be able to return ...
1717 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001718 //
1719 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001720 if (!outer.getBounds().contains(inner.getBounds())) {
1721 return;
1722 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001723
1724 this->onDrawDRRect(outer, inner, paint);
1725}
1726
reed41af9662015-01-05 07:49:08 -08001727// These need to stop being virtual -- clients need to override the onDraw... versions
1728
1729void SkCanvas::drawPaint(const SkPaint& paint) {
1730 this->onDrawPaint(paint);
1731}
1732
1733void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1734 this->onDrawRect(r, paint);
1735}
1736
msarettdca352e2016-08-26 06:37:45 -07001737void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1738 if (region.isEmpty()) {
1739 return;
1740 }
1741
1742 if (region.isRect()) {
1743 return this->drawIRect(region.getBounds(), paint);
1744 }
1745
1746 this->onDrawRegion(region, paint);
1747}
1748
reed41af9662015-01-05 07:49:08 -08001749void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1750 this->onDrawOval(r, paint);
1751}
1752
1753void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1754 this->onDrawRRect(rrect, paint);
1755}
1756
1757void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1758 this->onDrawPoints(mode, count, pts, paint);
1759}
1760
Mike Reede88a1cb2017-03-17 09:50:46 -04001761void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1762 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001763 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001764 this->onDrawVerticesObject(vertices.get(), mode, paint);
1765}
1766
1767void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1768 RETURN_ON_NULL(vertices);
1769 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001770}
1771
1772void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1773 this->onDrawPath(path, paint);
1774}
1775
reeda85d4d02015-05-06 12:56:48 -07001776void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001777 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001778 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001779}
1780
reede47829b2015-08-06 10:02:53 -07001781void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1782 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001783 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001784 if (dst.isEmpty() || src.isEmpty()) {
1785 return;
1786 }
1787 this->onDrawImageRect(image, &src, dst, paint, constraint);
1788}
reed41af9662015-01-05 07:49:08 -08001789
reed84984ef2015-07-17 07:09:43 -07001790void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1791 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001792 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001793 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001794}
1795
reede47829b2015-08-06 10:02:53 -07001796void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1797 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001798 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001799 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1800 constraint);
1801}
reede47829b2015-08-06 10:02:53 -07001802
reed4c21dc52015-06-25 12:32:03 -07001803void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1804 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001805 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001806 if (dst.isEmpty()) {
1807 return;
1808 }
msarett552bca92016-08-03 06:53:26 -07001809 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1810 this->onDrawImageNine(image, center, dst, paint);
1811 } else {
reede47829b2015-08-06 10:02:53 -07001812 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001813 }
reed4c21dc52015-06-25 12:32:03 -07001814}
1815
msarett16882062016-08-16 09:31:08 -07001816void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1817 const SkPaint* paint) {
1818 RETURN_ON_NULL(image);
1819 if (dst.isEmpty()) {
1820 return;
1821 }
msarett71df2d72016-09-30 12:41:42 -07001822
1823 SkIRect bounds;
1824 Lattice latticePlusBounds = lattice;
1825 if (!latticePlusBounds.fBounds) {
1826 bounds = SkIRect::MakeWH(image->width(), image->height());
1827 latticePlusBounds.fBounds = &bounds;
1828 }
1829
1830 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1831 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001832 } else {
1833 this->drawImageRect(image, dst, paint);
1834 }
1835}
1836
reed41af9662015-01-05 07:49:08 -08001837void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001838 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001839 return;
1840 }
reed41af9662015-01-05 07:49:08 -08001841 this->onDrawBitmap(bitmap, dx, dy, paint);
1842}
1843
reede47829b2015-08-06 10:02:53 -07001844void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001845 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001846 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001847 return;
1848 }
reede47829b2015-08-06 10:02:53 -07001849 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001850}
1851
reed84984ef2015-07-17 07:09:43 -07001852void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1853 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001854 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001855}
1856
reede47829b2015-08-06 10:02:53 -07001857void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1858 SrcRectConstraint constraint) {
1859 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1860 constraint);
1861}
reede47829b2015-08-06 10:02:53 -07001862
reed41af9662015-01-05 07:49:08 -08001863void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1864 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001865 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001866 return;
1867 }
msarett552bca92016-08-03 06:53:26 -07001868 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1869 this->onDrawBitmapNine(bitmap, center, dst, paint);
1870 } else {
reeda5517e22015-07-14 10:54:12 -07001871 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001872 }
reed41af9662015-01-05 07:49:08 -08001873}
1874
msarettc573a402016-08-02 08:05:56 -07001875void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1876 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001877 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001878 return;
1879 }
msarett71df2d72016-09-30 12:41:42 -07001880
1881 SkIRect bounds;
1882 Lattice latticePlusBounds = lattice;
1883 if (!latticePlusBounds.fBounds) {
1884 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1885 latticePlusBounds.fBounds = &bounds;
1886 }
1887
1888 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1889 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001890 } else {
msarett16882062016-08-16 09:31:08 -07001891 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001892 }
msarettc573a402016-08-02 08:05:56 -07001893}
1894
reed71c3c762015-06-24 10:29:17 -07001895void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001896 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001897 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001898 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001899 if (count <= 0) {
1900 return;
1901 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001902 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001903 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001904 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001905}
1906
reedf70b5312016-03-04 16:36:20 -08001907void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1908 if (key) {
1909 this->onDrawAnnotation(rect, key, value);
1910 }
1911}
1912
reede47829b2015-08-06 10:02:53 -07001913void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1914 const SkPaint* paint, SrcRectConstraint constraint) {
1915 if (src) {
1916 this->drawImageRect(image, *src, dst, paint, constraint);
1917 } else {
1918 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1919 dst, paint, constraint);
1920 }
1921}
1922void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1923 const SkPaint* paint, SrcRectConstraint constraint) {
1924 if (src) {
1925 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1926 } else {
1927 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1928 dst, paint, constraint);
1929 }
1930}
1931
tomhudsoncb3bd182016-05-18 07:24:16 -07001932void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1933 SkIRect layer_bounds = this->getTopLayerBounds();
1934 if (matrix) {
1935 *matrix = this->getTotalMatrix();
1936 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1937 }
1938 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001939 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001940 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1941 }
1942}
1943
reed@android.com8a1c16f2008-12-17 15:59:43 +00001944//////////////////////////////////////////////////////////////////////////////
1945// These are the virtual drawing methods
1946//////////////////////////////////////////////////////////////////////////////
1947
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001948void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001949 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001950 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1951 }
1952}
1953
reed41af9662015-01-05 07:49:08 -08001954void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001955 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001956 this->internalDrawPaint(paint);
1957}
1958
1959void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001960 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001961
1962 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001963 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001964 }
1965
reed@google.com4e2b3d32011-04-07 14:18:59 +00001966 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001967}
1968
reed41af9662015-01-05 07:49:08 -08001969void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1970 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001971 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001972 if ((long)count <= 0) {
1973 return;
1974 }
1975
Mike Reed822128b2017-02-28 16:41:03 -05001976 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001977 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001978 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001979 // special-case 2 points (common for drawing a single line)
1980 if (2 == count) {
1981 r.set(pts[0], pts[1]);
1982 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001983 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001984 }
Mike Reed822128b2017-02-28 16:41:03 -05001985 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001986 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1987 return;
1988 }
1989 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001990 }
reed@google.coma584aed2012-05-16 14:06:02 +00001991
halcanary96fcdcc2015-08-27 07:41:13 -07001992 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001993
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001994 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001995
reed@android.com8a1c16f2008-12-17 15:59:43 +00001996 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001997 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998 }
reed@google.com4b226022011-01-11 18:32:13 +00001999
reed@google.com4e2b3d32011-04-07 14:18:59 +00002000 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002001}
2002
reed4a167172016-08-18 17:15:25 -07002003static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2004 return ((intptr_t)paint.getImageFilter() |
2005#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2006 (intptr_t)canvas->getDrawFilter() |
2007#endif
2008 (intptr_t)paint.getLooper() ) != 0;
2009}
2010
reed41af9662015-01-05 07:49:08 -08002011void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002012 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002013 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002014 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2015 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2016 SkRect tmp(r);
2017 tmp.sort();
2018
Mike Reed822128b2017-02-28 16:41:03 -05002019 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002020 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2021 return;
2022 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002023 }
reed@google.com4b226022011-01-11 18:32:13 +00002024
reed4a167172016-08-18 17:15:25 -07002025 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002026 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002027
reed4a167172016-08-18 17:15:25 -07002028 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002029 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002030 }
2031
2032 LOOPER_END
2033 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002034 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002035 SkDrawIter iter(this);
2036 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002037 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002038 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002039 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002040}
2041
msarett44df6512016-08-25 13:54:30 -07002042void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002043 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002044 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002045 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002046 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2047 return;
2048 }
msarett44df6512016-08-25 13:54:30 -07002049 }
2050
Mike Reed822128b2017-02-28 16:41:03 -05002051 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002052
2053 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002054 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002055 }
2056
2057 LOOPER_END
2058}
2059
reed41af9662015-01-05 07:49:08 -08002060void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002061 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002062 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002063 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002064 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2065 return;
2066 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002067 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002068
Mike Reed822128b2017-02-28 16:41:03 -05002069 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002070
2071 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002072 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002073 }
2074
2075 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002076}
2077
bsalomonac3aa242016-08-19 11:25:19 -07002078void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2079 SkScalar sweepAngle, bool useCenter,
2080 const SkPaint& paint) {
2081 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002082 if (paint.canComputeFastBounds()) {
2083 SkRect storage;
2084 // Note we're using the entire oval as the bounds.
2085 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2086 return;
2087 }
bsalomonac3aa242016-08-19 11:25:19 -07002088 }
2089
Mike Reed822128b2017-02-28 16:41:03 -05002090 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002091
2092 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002093 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002094 }
2095
2096 LOOPER_END
2097}
2098
reed41af9662015-01-05 07:49:08 -08002099void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002100 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002101 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002102 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002103 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2104 return;
2105 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002106 }
2107
2108 if (rrect.isRect()) {
2109 // call the non-virtual version
2110 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002111 return;
2112 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002113 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002114 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2115 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002116 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002117
Mike Reed822128b2017-02-28 16:41:03 -05002118 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002119
2120 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002121 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002122 }
2123
2124 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002125}
2126
Mike Reed822128b2017-02-28 16:41:03 -05002127void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002128 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002129 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002130 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2131 return;
2132 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002133 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002134
Mike Reed822128b2017-02-28 16:41:03 -05002135 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002136
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002137 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002138 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002139 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002140
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002141 LOOPER_END
2142}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002143
reed41af9662015-01-05 07:49:08 -08002144void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002145 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002146 if (!path.isFinite()) {
2147 return;
2148 }
2149
Mike Reed822128b2017-02-28 16:41:03 -05002150 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002151 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002152 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002153 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2154 return;
2155 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002156 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002157
Mike Reed822128b2017-02-28 16:41:03 -05002158 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002159 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002160 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002161 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002162 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002163 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002164
Mike Reed822128b2017-02-28 16:41:03 -05002165 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002166
2167 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002168 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002169 }
2170
reed@google.com4e2b3d32011-04-07 14:18:59 +00002171 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002172}
2173
reed262a71b2015-12-05 13:07:27 -08002174bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002175 if (!paint.getImageFilter()) {
2176 return false;
2177 }
2178
2179 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002180 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002181 return false;
2182 }
2183
2184 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2185 // Once we can filter and the filter will return a result larger than itself, we should be
2186 // able to remove this constraint.
2187 // skbug.com/4526
2188 //
2189 SkPoint pt;
2190 ctm.mapXY(x, y, &pt);
2191 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2192 return ir.contains(fMCRec->fRasterClip.getBounds());
2193}
2194
reeda85d4d02015-05-06 12:56:48 -07002195void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002196 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002197 SkRect bounds = SkRect::MakeXYWH(x, y,
2198 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002199 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002200 SkRect tmp = bounds;
2201 if (paint) {
2202 paint->computeFastBounds(tmp, &tmp);
2203 }
2204 if (this->quickReject(tmp)) {
2205 return;
2206 }
reeda85d4d02015-05-06 12:56:48 -07002207 }
halcanary9d524f22016-03-29 09:03:52 -07002208
reeda85d4d02015-05-06 12:56:48 -07002209 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002210 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002211 paint = lazy.init();
2212 }
reed262a71b2015-12-05 13:07:27 -08002213
reeda2217ef2016-07-20 06:04:34 -07002214 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002215 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2216 *paint);
2217 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002218 special = this->getDevice()->makeSpecial(image);
2219 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002220 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002221 }
2222 }
2223
reed262a71b2015-12-05 13:07:27 -08002224 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2225
reeda85d4d02015-05-06 12:56:48 -07002226 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002227 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002228 if (special) {
2229 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002230 iter.fDevice->ctm().mapXY(x, y, &pt);
2231 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002232 SkScalarRoundToInt(pt.fX),
2233 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002234 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002235 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002236 }
reeda85d4d02015-05-06 12:56:48 -07002237 }
halcanary9d524f22016-03-29 09:03:52 -07002238
reeda85d4d02015-05-06 12:56:48 -07002239 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002240}
2241
reed41af9662015-01-05 07:49:08 -08002242void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002243 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002244 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002245 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002246 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002247 if (paint) {
2248 paint->computeFastBounds(dst, &storage);
2249 }
2250 if (this->quickReject(storage)) {
2251 return;
2252 }
reeda85d4d02015-05-06 12:56:48 -07002253 }
2254 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002255 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002256 paint = lazy.init();
2257 }
halcanary9d524f22016-03-29 09:03:52 -07002258
senorblancoc41e7e12015-12-07 12:51:30 -08002259 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002260 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002261
reeda85d4d02015-05-06 12:56:48 -07002262 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002263 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002264 }
halcanary9d524f22016-03-29 09:03:52 -07002265
reeda85d4d02015-05-06 12:56:48 -07002266 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002267}
2268
reed41af9662015-01-05 07:49:08 -08002269void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002270 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002271 SkDEBUGCODE(bitmap.validate();)
2272
reed33366972015-10-08 09:22:02 -07002273 if (bitmap.drawsNothing()) {
2274 return;
2275 }
2276
2277 SkLazyPaint lazy;
2278 if (nullptr == paint) {
2279 paint = lazy.init();
2280 }
2281
Mike Reed822128b2017-02-28 16:41:03 -05002282 SkRect bounds;
2283 bitmap.getBounds(&bounds);
2284 bounds.offset(x, y);
2285 bool canFastBounds = paint->canComputeFastBounds();
2286 if (canFastBounds) {
2287 SkRect storage;
2288 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002289 return;
2290 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002291 }
reed@google.com4b226022011-01-11 18:32:13 +00002292
reeda2217ef2016-07-20 06:04:34 -07002293 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002294 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2295 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002296 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002297 special = this->getDevice()->makeSpecial(bitmap);
2298 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002299 drawAsSprite = false;
2300 }
2301 }
2302
Mike Reed822128b2017-02-28 16:41:03 -05002303 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2304
2305 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002306
2307 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002308 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002309 if (special) {
reed262a71b2015-12-05 13:07:27 -08002310 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002311 iter.fDevice->ctm().mapXY(x, y, &pt);
2312 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002313 SkScalarRoundToInt(pt.fX),
2314 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002315 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002316 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002317 }
reed33366972015-10-08 09:22:02 -07002318 }
msarettfbfa2582016-08-12 08:29:08 -07002319
reed33366972015-10-08 09:22:02 -07002320 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002321}
2322
reed@google.com9987ec32011-09-07 11:57:52 +00002323// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002324void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002325 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002326 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002327 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328 return;
2329 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002330
halcanary96fcdcc2015-08-27 07:41:13 -07002331 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002332 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002333 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2334 return;
2335 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002336 }
reed@google.com3d608122011-11-21 15:16:16 +00002337
reed@google.com33535f32012-09-25 15:37:50 +00002338 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002339 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002340 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002341 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002342
senorblancoc41e7e12015-12-07 12:51:30 -08002343 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002344 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002345
reed@google.com33535f32012-09-25 15:37:50 +00002346 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002347 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002348 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002349
reed@google.com33535f32012-09-25 15:37:50 +00002350 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002351}
2352
reed41af9662015-01-05 07:49:08 -08002353void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002354 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002355 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002356 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002357 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002358}
2359
reed4c21dc52015-06-25 12:32:03 -07002360void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2361 const SkPaint* paint) {
2362 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002363
halcanary96fcdcc2015-08-27 07:41:13 -07002364 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002365 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002366 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2367 return;
2368 }
reed@google.com3d608122011-11-21 15:16:16 +00002369 }
halcanary9d524f22016-03-29 09:03:52 -07002370
reed4c21dc52015-06-25 12:32:03 -07002371 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002372 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002373 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002374 }
halcanary9d524f22016-03-29 09:03:52 -07002375
senorblancoc41e7e12015-12-07 12:51:30 -08002376 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002377
reed4c21dc52015-06-25 12:32:03 -07002378 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002379 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002380 }
halcanary9d524f22016-03-29 09:03:52 -07002381
reed4c21dc52015-06-25 12:32:03 -07002382 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002383}
2384
reed41af9662015-01-05 07:49:08 -08002385void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2386 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002387 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002388 SkDEBUGCODE(bitmap.validate();)
2389
halcanary96fcdcc2015-08-27 07:41:13 -07002390 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002391 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002392 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2393 return;
2394 }
reed4c21dc52015-06-25 12:32:03 -07002395 }
halcanary9d524f22016-03-29 09:03:52 -07002396
reed4c21dc52015-06-25 12:32:03 -07002397 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002398 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002399 paint = lazy.init();
2400 }
halcanary9d524f22016-03-29 09:03:52 -07002401
senorblancoc41e7e12015-12-07 12:51:30 -08002402 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002403
reed4c21dc52015-06-25 12:32:03 -07002404 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002405 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002406 }
halcanary9d524f22016-03-29 09:03:52 -07002407
reed4c21dc52015-06-25 12:32:03 -07002408 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002409}
2410
msarett16882062016-08-16 09:31:08 -07002411void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2412 const SkPaint* paint) {
2413 if (nullptr == paint || paint->canComputeFastBounds()) {
2414 SkRect storage;
2415 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2416 return;
2417 }
2418 }
2419
2420 SkLazyPaint lazy;
2421 if (nullptr == paint) {
2422 paint = lazy.init();
2423 }
2424
2425 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2426
2427 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002428 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002429 }
2430
2431 LOOPER_END
2432}
2433
2434void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2435 const SkRect& dst, const SkPaint* paint) {
2436 if (nullptr == paint || paint->canComputeFastBounds()) {
2437 SkRect storage;
2438 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2439 return;
2440 }
2441 }
2442
2443 SkLazyPaint lazy;
2444 if (nullptr == paint) {
2445 paint = lazy.init();
2446 }
2447
2448 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2449
2450 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002451 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002452 }
2453
2454 LOOPER_END
2455}
2456
reed@google.comf67e4cf2011-03-15 20:56:58 +00002457class SkDeviceFilteredPaint {
2458public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002459 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002460 uint32_t filteredFlags = device->filterTextFlags(paint);
2461 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002462 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002463 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002464 fPaint = newPaint;
2465 } else {
2466 fPaint = &paint;
2467 }
2468 }
2469
reed@google.comf67e4cf2011-03-15 20:56:58 +00002470 const SkPaint& paint() const { return *fPaint; }
2471
2472private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002473 const SkPaint* fPaint;
2474 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002475};
2476
reed@google.come0d9ce82014-04-23 04:00:17 +00002477void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2478 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002479 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480
2481 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002482 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002483 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484 }
2485
reed@google.com4e2b3d32011-04-07 14:18:59 +00002486 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002487}
2488
reed@google.come0d9ce82014-04-23 04:00:17 +00002489void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2490 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002491 SkPoint textOffset = SkPoint::Make(0, 0);
2492
halcanary96fcdcc2015-08-27 07:41:13 -07002493 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002494
reed@android.com8a1c16f2008-12-17 15:59:43 +00002495 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002496 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002497 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002498 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002499 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002500
reed@google.com4e2b3d32011-04-07 14:18:59 +00002501 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002502}
2503
reed@google.come0d9ce82014-04-23 04:00:17 +00002504void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2505 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002506
2507 SkPoint textOffset = SkPoint::Make(0, constY);
2508
halcanary96fcdcc2015-08-27 07:41:13 -07002509 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002510
reed@android.com8a1c16f2008-12-17 15:59:43 +00002511 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002512 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002513 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002514 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002515 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002516
reed@google.com4e2b3d32011-04-07 14:18:59 +00002517 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002518}
2519
reed@google.come0d9ce82014-04-23 04:00:17 +00002520void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2521 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002522 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002523
reed@android.com8a1c16f2008-12-17 15:59:43 +00002524 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002525 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002526 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002527 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002528
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002529 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002530}
2531
reed45561a02016-07-07 12:47:17 -07002532void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2533 const SkRect* cullRect, const SkPaint& paint) {
2534 if (cullRect && this->quickReject(*cullRect)) {
2535 return;
2536 }
2537
2538 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2539
2540 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002541 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002542 }
2543
2544 LOOPER_END
2545}
2546
fmalita00d5c2c2014-08-21 08:53:26 -07002547void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2548 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002549
fmalita85d5eb92015-03-04 11:20:12 -08002550 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002551 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002552 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002553 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002554 SkRect tmp;
2555 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2556 return;
2557 }
2558 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002559 }
2560
fmalita024f9962015-03-03 19:08:17 -08002561 // We cannot filter in the looper as we normally do, because the paint is
2562 // incomplete at this point (text-related attributes are embedded within blob run paints).
2563 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002564 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002565
fmalita85d5eb92015-03-04 11:20:12 -08002566 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002567
fmalitaaa1b9122014-08-28 14:32:24 -07002568 while (iter.next()) {
2569 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002570 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002571 }
2572
fmalitaaa1b9122014-08-28 14:32:24 -07002573 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002574
2575 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002576}
2577
reed@google.come0d9ce82014-04-23 04:00:17 +00002578// These will become non-virtual, so they always call the (virtual) onDraw... method
2579void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2580 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002581 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002582 if (byteLength) {
2583 this->onDrawText(text, byteLength, x, y, paint);
2584 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002585}
2586void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2587 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002588 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002589 if (byteLength) {
2590 this->onDrawPosText(text, byteLength, pos, paint);
2591 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002592}
2593void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2594 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002595 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002596 if (byteLength) {
2597 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2598 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002599}
2600void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2601 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002602 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002603 if (byteLength) {
2604 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2605 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002606}
reed45561a02016-07-07 12:47:17 -07002607void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2608 const SkRect* cullRect, const SkPaint& paint) {
2609 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2610 if (byteLength) {
2611 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2612 }
2613}
fmalita00d5c2c2014-08-21 08:53:26 -07002614void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2615 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002616 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002617 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002618 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002619}
reed@google.come0d9ce82014-04-23 04:00:17 +00002620
Mike Reede88a1cb2017-03-17 09:50:46 -04002621void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2622 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002623 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2624 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2625
2626 while (iter.next()) {
2627 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002628 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002629 }
2630
2631 LOOPER_END
2632}
2633
dandovb3c9d1c2014-08-12 08:34:29 -07002634void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002635 const SkPoint texCoords[4], SkBlendMode bmode,
2636 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002637 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002638 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002639 return;
2640 }
mtklein6cfa73a2014-08-13 13:33:49 -07002641
Mike Reedfaba3712016-11-03 14:45:31 -04002642 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002643}
2644
2645void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002646 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002647 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002648 // Since a patch is always within the convex hull of the control points, we discard it when its
2649 // bounding rectangle is completely outside the current clip.
2650 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002651 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002652 if (this->quickReject(bounds)) {
2653 return;
2654 }
mtklein6cfa73a2014-08-13 13:33:49 -07002655
halcanary96fcdcc2015-08-27 07:41:13 -07002656 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002657
dandovecfff212014-08-04 10:02:00 -07002658 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002659 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002660 }
mtklein6cfa73a2014-08-13 13:33:49 -07002661
dandovecfff212014-08-04 10:02:00 -07002662 LOOPER_END
2663}
2664
reeda8db7282015-07-07 10:22:31 -07002665void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002666 RETURN_ON_NULL(dr);
2667 if (x || y) {
2668 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2669 this->onDrawDrawable(dr, &matrix);
2670 } else {
2671 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002672 }
2673}
2674
reeda8db7282015-07-07 10:22:31 -07002675void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002676 RETURN_ON_NULL(dr);
2677 if (matrix && matrix->isIdentity()) {
2678 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002679 }
reede3b38ce2016-01-08 09:18:44 -08002680 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002681}
2682
2683void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002684 // drawable bounds are no longer reliable (e.g. android displaylist)
2685 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002686 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002687}
2688
reed71c3c762015-06-24 10:29:17 -07002689void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002690 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002691 const SkRect* cull, const SkPaint* paint) {
2692 if (cull && this->quickReject(*cull)) {
2693 return;
2694 }
2695
2696 SkPaint pnt;
2697 if (paint) {
2698 pnt = *paint;
2699 }
halcanary9d524f22016-03-29 09:03:52 -07002700
halcanary96fcdcc2015-08-27 07:41:13 -07002701 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002702 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002703 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002704 }
2705 LOOPER_END
2706}
2707
reedf70b5312016-03-04 16:36:20 -08002708void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2709 SkASSERT(key);
2710
2711 SkPaint paint;
2712 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2713 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002714 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002715 }
2716 LOOPER_END
2717}
2718
reed@android.com8a1c16f2008-12-17 15:59:43 +00002719//////////////////////////////////////////////////////////////////////////////
2720// These methods are NOT virtual, and therefore must call back into virtual
2721// methods, rather than actually drawing themselves.
2722//////////////////////////////////////////////////////////////////////////////
2723
reed374772b2016-10-05 17:33:02 -07002724void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002725 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726 SkPaint paint;
2727
2728 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002729 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730 this->drawPaint(paint);
2731}
2732
2733void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002734 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002735 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002736 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2737}
2738
Mike Reed3661bc92017-02-22 13:21:42 -05002739void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002740 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002742
reed@android.com8a1c16f2008-12-17 15:59:43 +00002743 pts[0].set(x0, y0);
2744 pts[1].set(x1, y1);
2745 this->drawPoints(kLines_PointMode, 2, pts, paint);
2746}
2747
Mike Reed3661bc92017-02-22 13:21:42 -05002748void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002749 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002750 if (radius < 0) {
2751 radius = 0;
2752 }
2753
2754 SkRect r;
2755 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002756 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002757}
2758
2759void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2760 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002761 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002763 SkRRect rrect;
2764 rrect.setRectXY(r, rx, ry);
2765 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766 } else {
2767 this->drawRect(r, paint);
2768 }
2769}
2770
reed@android.com8a1c16f2008-12-17 15:59:43 +00002771void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2772 SkScalar sweepAngle, bool useCenter,
2773 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002774 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002775 if (oval.isEmpty() || !sweepAngle) {
2776 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777 }
bsalomon21af9ca2016-08-25 12:29:23 -07002778 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779}
2780
2781void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2782 const SkPath& path, SkScalar hOffset,
2783 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002784 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002785 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002786
reed@android.com8a1c16f2008-12-17 15:59:43 +00002787 matrix.setTranslate(hOffset, vOffset);
2788 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2789}
2790
reed@android.comf76bacf2009-05-13 14:00:33 +00002791///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002792
2793/**
2794 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2795 * against the playback cost of recursing into the subpicture to get at its actual ops.
2796 *
2797 * For now we pick a conservatively small value, though measurement (and other heuristics like
2798 * the type of ops contained) may justify changing this value.
2799 */
2800#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002801
reedd5fa1a42014-08-09 11:08:05 -07002802void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002803 RETURN_ON_NULL(picture);
2804
reed1c2c4412015-04-30 13:09:24 -07002805 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002806 if (matrix && matrix->isIdentity()) {
2807 matrix = nullptr;
2808 }
2809 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2810 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2811 picture->playback(this);
2812 } else {
2813 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002814 }
2815}
robertphillips9b14f262014-06-04 05:40:44 -07002816
reedd5fa1a42014-08-09 11:08:05 -07002817void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2818 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002819 if (!paint || paint->canComputeFastBounds()) {
2820 SkRect bounds = picture->cullRect();
2821 if (paint) {
2822 paint->computeFastBounds(bounds, &bounds);
2823 }
2824 if (matrix) {
2825 matrix->mapRect(&bounds);
2826 }
2827 if (this->quickReject(bounds)) {
2828 return;
2829 }
2830 }
2831
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002832 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002833 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002834}
2835
vjiaoblack95302da2016-07-21 10:25:54 -07002836#ifdef SK_EXPERIMENTAL_SHADOWING
2837void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2838 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002839 const SkPaint* paint,
2840 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002841 RETURN_ON_NULL(picture);
2842
2843 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2844
vjiaoblacke6f5d562016-08-25 06:30:23 -07002845 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002846}
2847
2848void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2849 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002850 const SkPaint* paint,
2851 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002852 if (!paint || paint->canComputeFastBounds()) {
2853 SkRect bounds = picture->cullRect();
2854 if (paint) {
2855 paint->computeFastBounds(bounds, &bounds);
2856 }
2857 if (matrix) {
2858 matrix->mapRect(&bounds);
2859 }
2860 if (this->quickReject(bounds)) {
2861 return;
2862 }
2863 }
2864
2865 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2866
vjiaoblacke6f5d562016-08-25 06:30:23 -07002867 sk_sp<SkImage> povDepthMap;
2868 sk_sp<SkImage> diffuseMap;
2869
vjiaoblack904527d2016-08-09 09:32:09 -07002870 // povDepthMap
2871 {
2872 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002873 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2874 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002875 sk_sp<SkLights> povLight = builder.finish();
2876
2877 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2878 picture->cullRect().height(),
2879 kBGRA_8888_SkColorType,
2880 kOpaque_SkAlphaType);
2881
2882 // Create a new surface (that matches the backend of canvas)
2883 // to create the povDepthMap
2884 sk_sp<SkSurface> surf(this->makeSurface(info));
2885
2886 // Wrap another SPFCanvas around the surface
2887 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2888 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2889
2890 // set the depth map canvas to have the light as the user's POV
2891 depthMapCanvas->setLights(std::move(povLight));
2892
2893 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002894 povDepthMap = surf->makeImageSnapshot();
2895 }
2896
2897 // diffuseMap
2898 {
2899 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2900 picture->cullRect().height(),
2901 kBGRA_8888_SkColorType,
2902 kOpaque_SkAlphaType);
2903
2904 sk_sp<SkSurface> surf(this->makeSurface(info));
2905 surf->getCanvas()->drawPicture(picture);
2906
2907 diffuseMap = surf->makeImageSnapshot();
2908 }
vjiaoblack904527d2016-08-09 09:32:09 -07002909
2910 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
2911 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07002912 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
2913 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07002914
2915 // TODO: pass the depth to the shader in vertices, or uniforms
2916 // so we don't have to render depth and color separately
2917 for (int i = 0; i < fLights->numLights(); ++i) {
2918 // skip over ambient lights; they don't cast shadows
2919 // lights that have shadow maps do not need updating (because lights are immutable)
2920 sk_sp<SkImage> depthMap;
2921 SkISize shMapSize;
2922
2923 if (fLights->light(i).getShadowMap() != nullptr) {
2924 continue;
2925 }
2926
2927 if (fLights->light(i).isRadial()) {
2928 shMapSize.fHeight = 1;
2929 shMapSize.fWidth = (int) picture->cullRect().width();
2930
2931 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
2932 kBGRA_8888_SkColorType,
2933 kOpaque_SkAlphaType);
2934
2935 // Create new surface (that matches the backend of canvas)
2936 // for each shadow map
2937 sk_sp<SkSurface> surf(this->makeSurface(info));
2938
2939 // Wrap another SPFCanvas around the surface
2940 SkCanvas* depthMapCanvas = surf->getCanvas();
2941
2942 SkLights::Builder builder;
2943 builder.add(fLights->light(i));
2944 sk_sp<SkLights> curLight = builder.finish();
2945
2946 sk_sp<SkShader> shadowMapShader;
2947 shadowMapShader = SkRadialShadowMapShader::Make(
2948 povDepthShader, curLight,
2949 (int) picture->cullRect().width(),
2950 (int) picture->cullRect().height());
2951
2952 SkPaint shadowMapPaint;
2953 shadowMapPaint.setShader(std::move(shadowMapShader));
2954
2955 depthMapCanvas->setLights(curLight);
2956
2957 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
2958 diffuseMap->height()),
2959 shadowMapPaint);
2960
2961 depthMap = surf->makeImageSnapshot();
2962
2963 } else {
2964 // TODO: compute the correct size of the depth map from the light properties
2965 // TODO: maybe add a kDepth_8_SkColorType
2966 // TODO: find actual max depth of picture
2967 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
2968 fLights->light(i), 255,
2969 (int) picture->cullRect().width(),
2970 (int) picture->cullRect().height());
2971
2972 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
2973 kBGRA_8888_SkColorType,
2974 kOpaque_SkAlphaType);
2975
2976 // Create a new surface (that matches the backend of canvas)
2977 // for each shadow map
2978 sk_sp<SkSurface> surf(this->makeSurface(info));
2979
2980 // Wrap another SPFCanvas around the surface
2981 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2982 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2983 depthMapCanvas->setShadowParams(params);
2984
2985 // set the depth map canvas to have the light we're drawing.
2986 SkLights::Builder builder;
2987 builder.add(fLights->light(i));
2988 sk_sp<SkLights> curLight = builder.finish();
2989 depthMapCanvas->setLights(std::move(curLight));
2990
2991 depthMapCanvas->drawPicture(picture);
2992 depthMap = surf->makeImageSnapshot();
2993 }
2994
2995 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
2996 fLights->light(i).setShadowMap(std::move(depthMap));
2997 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
2998 // we blur the variance map
2999 SkPaint blurPaint;
3000 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3001 params.fShadowRadius, nullptr));
3002
3003 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3004 kBGRA_8888_SkColorType,
3005 kOpaque_SkAlphaType);
3006
3007 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3008
3009 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3010
3011 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3012 }
3013 }
3014
3015 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003016 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3017 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003018 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003019 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003020 diffuseMap->height(),
3021 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003022
3023 shadowPaint.setShader(shadowShader);
3024
3025 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003026}
3027#endif
3028
reed@android.com8a1c16f2008-12-17 15:59:43 +00003029///////////////////////////////////////////////////////////////////////////////
3030///////////////////////////////////////////////////////////////////////////////
3031
reed3aafe112016-08-18 12:45:34 -07003032SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003033 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003034
3035 SkASSERT(canvas);
3036
reed3aafe112016-08-18 12:45:34 -07003037 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003038 fDone = !fImpl->next();
3039}
3040
3041SkCanvas::LayerIter::~LayerIter() {
3042 fImpl->~SkDrawIter();
3043}
3044
3045void SkCanvas::LayerIter::next() {
3046 fDone = !fImpl->next();
3047}
3048
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003049SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003050 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003051}
3052
3053const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003054 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003055}
3056
3057const SkPaint& SkCanvas::LayerIter::paint() const {
3058 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003059 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003060 paint = &fDefaultPaint;
3061 }
3062 return *paint;
3063}
3064
Mike Reeda1361362017-03-07 09:37:29 -05003065void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3066 return fImpl->fDevice->onAsRgnClip(rgn);
3067}
3068
reed@android.com8a1c16f2008-12-17 15:59:43 +00003069int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3070int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003071
3072///////////////////////////////////////////////////////////////////////////////
3073
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003074static bool supported_for_raster_canvas(const SkImageInfo& info) {
3075 switch (info.alphaType()) {
3076 case kPremul_SkAlphaType:
3077 case kOpaque_SkAlphaType:
3078 break;
3079 default:
3080 return false;
3081 }
3082
3083 switch (info.colorType()) {
3084 case kAlpha_8_SkColorType:
3085 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003086 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003087 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003088 break;
3089 default:
3090 return false;
3091 }
3092
3093 return true;
3094}
3095
Mike Reed5df49342016-11-12 08:06:55 -06003096std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3097 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003098 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003099 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003100 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003101
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003102 SkBitmap bitmap;
3103 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003104 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003105 }
Mike Reed5df49342016-11-12 08:06:55 -06003106 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003107}
reedd5fa1a42014-08-09 11:08:05 -07003108
3109///////////////////////////////////////////////////////////////////////////////
3110
3111SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003112 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003113 : fCanvas(canvas)
3114 , fSaveCount(canvas->getSaveCount())
3115{
bsalomon49f085d2014-09-05 13:34:00 -07003116 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003117 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003118 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003119 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003120 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003121 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003122 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003123 canvas->save();
3124 }
mtklein6cfa73a2014-08-13 13:33:49 -07003125
bsalomon49f085d2014-09-05 13:34:00 -07003126 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003127 canvas->concat(*matrix);
3128 }
3129}
3130
3131SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3132 fCanvas->restoreToCount(fSaveCount);
3133}
reede8f30622016-03-23 18:59:25 -07003134
Florin Malitaee424ac2016-12-01 12:47:59 -05003135///////////////////////////////////////////////////////////////////////////////
3136
3137SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3138 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3139
Florin Malita439ace92016-12-02 12:05:41 -05003140SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3141 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3142
Florin Malitaee424ac2016-12-01 12:47:59 -05003143SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3144 (void)this->INHERITED::getSaveLayerStrategy(rec);
3145 return kNoLayer_SaveLayerStrategy;
3146}
3147
3148///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003149
reed73603f32016-09-20 08:42:38 -07003150static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3151static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3152static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3153static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3154static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3155static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003156
3157///////////////////////////////////////////////////////////////////////////////////////////////////
3158
3159SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3160 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04003161 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05003162 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3163 SkIPoint origin = dev->getOrigin();
3164 SkMatrix ctm = this->getTotalMatrix();
3165 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3166
3167 SkIRect clip = fMCRec->fRasterClip.getBounds();
3168 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003169 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003170 clip.setEmpty();
3171 }
3172
3173 fAllocator->updateHandle(handle, ctm, clip);
3174 return handle;
3175 }
3176 return nullptr;
3177}
3178
3179static bool install(SkBitmap* bm, const SkImageInfo& info,
3180 const SkRasterHandleAllocator::Rec& rec) {
3181 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3182 rec.fReleaseProc, rec.fReleaseCtx);
3183}
3184
3185SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3186 SkBitmap* bm) {
3187 SkRasterHandleAllocator::Rec rec;
3188 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3189 return nullptr;
3190 }
3191 return rec.fHandle;
3192}
3193
3194std::unique_ptr<SkCanvas>
3195SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3196 const SkImageInfo& info, const Rec* rec) {
3197 if (!alloc || !supported_for_raster_canvas(info)) {
3198 return nullptr;
3199 }
3200
3201 SkBitmap bm;
3202 Handle hndl;
3203
3204 if (rec) {
3205 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3206 } else {
3207 hndl = alloc->allocBitmap(info, &bm);
3208 }
3209 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3210}