blob: 216d8fa952b3ecadfc38469fc880781c8b4b775b [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"
Florin Malitaab244f02017-05-03 19:16:58 +000023#include "SkLights.h"
Mike Reed5df49342016-11-12 08:06:55 -060024#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080025#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000026#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050027#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070028#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070029#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070030#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000031#include "SkPicture.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"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040036#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000037#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070038#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000039#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000040#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080041#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070042#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080045#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000046#include "GrRenderTarget.h"
Brian Osman3b655982017-03-07 16:58:08 -050047#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070048
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000049#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050050#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050051#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052
reede3b38ce2016-01-08 09:18:44 -080053#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
54
Mike Reed139e5e02017-03-08 11:29:33 -050055class SkNoPixelsDevice : public SkBaseDevice {
56public:
57 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
58 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
Mike Reed566e53c2017-03-10 10:49:45 -050059 {
Mike Reede393a622017-03-10 16:35:25 -050060 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
61 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050062 }
Mike Reed139e5e02017-03-08 11:29:33 -050063
64 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050065 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050066 this->privateResize(bounds.width(), bounds.height());
67 }
68
69protected:
70 // We don't track the clip at all (for performance), but we have to respond to some queries.
71 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
72 void onSave() override {}
73 void onRestore() override {}
74 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
75 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
76 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
77 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
78 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
79 bool onClipIsAA() const override { return false; }
80 void onAsRgnClip(SkRegion* rgn) const override {
81 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
82 }
83 ClipType onGetClipType() const override {
84 return kRect_ClipType;
85 }
86
87 void drawPaint(const SkPaint& paint) override {}
88 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
89 void drawRect(const SkRect&, const SkPaint&) override {}
90 void drawOval(const SkRect&, const SkPaint&) override {}
91 void drawRRect(const SkRRect&, const SkPaint&) override {}
92 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
93 void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {}
94 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
95 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
96 SkCanvas::SrcRectConstraint) override {}
97 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
98 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
99 const SkPaint&) override {}
100 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
Mike Reed2f6b5a42017-03-19 15:04:17 -0400101 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -0500102
103private:
104 typedef SkBaseDevice INHERITED;
105};
106
107///////////////////////////////////////////////////////////////////////////////////////////////////
108
reedc83a2972015-07-16 07:40:45 -0700109/*
110 * Return true if the drawing this rect would hit every pixels in the canvas.
111 *
112 * Returns false if
113 * - rect does not contain the canvas' bounds
114 * - paint is not fill
115 * - paint would blur or otherwise change the coverage of the rect
116 */
117bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
118 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700119 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
120 (int)kNone_ShaderOverrideOpacity,
121 "need_matching_enums0");
122 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
123 (int)kOpaque_ShaderOverrideOpacity,
124 "need_matching_enums1");
125 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
126 (int)kNotOpaque_ShaderOverrideOpacity,
127 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700128
129 const SkISize size = this->getBaseLayerSize();
130 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500131
132 // if we're clipped at all, we can't overwrite the entire surface
133 {
134 SkBaseDevice* base = this->getDevice();
135 SkBaseDevice* top = this->getTopDevice();
136 if (base != top) {
137 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
138 }
139 if (!base->clipIsWideOpen()) {
140 return false;
141 }
reedc83a2972015-07-16 07:40:45 -0700142 }
143
144 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700145 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700146 return false; // conservative
147 }
halcanaryc5769b22016-08-10 07:13:21 -0700148
149 SkRect devRect;
150 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
151 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700152 return false;
153 }
154 }
155
156 if (paint) {
157 SkPaint::Style paintStyle = paint->getStyle();
158 if (!(paintStyle == SkPaint::kFill_Style ||
159 paintStyle == SkPaint::kStrokeAndFill_Style)) {
160 return false;
161 }
162 if (paint->getMaskFilter() || paint->getLooper()
163 || paint->getPathEffect() || paint->getImageFilter()) {
164 return false; // conservative
165 }
166 }
167 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
168}
169
170///////////////////////////////////////////////////////////////////////////////////////////////////
171
reedd990e2f2014-12-22 11:58:30 -0800172static bool gIgnoreSaveLayerBounds;
173void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
174 gIgnoreSaveLayerBounds = ignore;
175}
176bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
177 return gIgnoreSaveLayerBounds;
178}
179
reed0acf1b42014-12-22 16:12:38 -0800180static bool gTreatSpriteAsBitmap;
181void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
182 gTreatSpriteAsBitmap = spriteAsBitmap;
183}
184bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
185 return gTreatSpriteAsBitmap;
186}
187
reed@google.comda17f752012-08-16 18:27:05 +0000188// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189//#define SK_TRACE_SAVERESTORE
190
191#ifdef SK_TRACE_SAVERESTORE
192 static int gLayerCounter;
193 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
194 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
195
196 static int gRecCounter;
197 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
198 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
199
200 static int gCanvasCounter;
201 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
202 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
203#else
204 #define inc_layer()
205 #define dec_layer()
206 #define inc_rec()
207 #define dec_rec()
208 #define inc_canvas()
209 #define dec_canvas()
210#endif
211
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000212typedef SkTLazy<SkPaint> SkLazyPaint;
213
reedc83a2972015-07-16 07:40:45 -0700214void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000215 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700216 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
217 ? SkSurface::kDiscard_ContentChangeMode
218 : SkSurface::kRetain_ContentChangeMode);
219 }
220}
221
222void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
223 ShaderOverrideOpacity overrideOpacity) {
224 if (fSurfaceBase) {
225 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
226 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
227 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
228 // and therefore we don't care which mode we're in.
229 //
230 if (fSurfaceBase->outstandingImageSnapshot()) {
231 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
232 mode = SkSurface::kDiscard_ContentChangeMode;
233 }
234 }
235 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000236 }
237}
238
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000241/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 The clip/matrix/proc are fields that reflect the top of the save/restore
243 stack. Whenever the canvas changes, it marks a dirty flag, and then before
244 these are used (assuming we're not on a layer) we rebuild these cache
245 values: they reflect the top of the save stack, but translated and clipped
246 by the device's XY offset and bitmap-bounds.
247*/
248struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400249 DeviceCM* fNext;
250 sk_sp<SkBaseDevice> fDevice;
251 SkRasterClip fClip;
252 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
253 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400254 sk_sp<SkImage> fClipImage;
255 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256
Florin Malita53f77bd2017-04-28 13:48:37 -0400257 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000258 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700259 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400260 , fDevice(std::move(device))
261 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700262 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000263 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400264 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400265 {}
reed@google.com4b226022011-01-11 18:32:13 +0000266
mtkleinfeaadee2015-04-08 11:25:48 -0700267 void reset(const SkIRect& bounds) {
268 SkASSERT(!fPaint);
269 SkASSERT(!fNext);
270 SkASSERT(fDevice);
271 fClip.setRect(bounds);
272 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273};
274
275/* This is the record we keep for each save/restore level in the stack.
276 Since a level optionally copies the matrix and/or stack, we have pointers
277 for these fields. If the value is copied for this level, the copy is
278 stored in the ...Storage field, and the pointer points to that. If the
279 value is not copied for this level, we ignore ...Storage, and just point
280 at the corresponding value in the previous level in the stack.
281*/
282class SkCanvas::MCRec {
283public:
reed1f836ee2014-07-07 07:49:34 -0700284 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700285 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000286 /* If there are any layers in the stack, this points to the top-most
287 one that is at or below this level in the stack (so we know what
288 bitmap/device to draw into from this level. This value is NOT
289 reference counted, since the real owner is either our fLayer field,
290 or a previous one in a lower level.)
291 */
Mike Reeda1361362017-03-07 09:37:29 -0500292 DeviceCM* fTopLayer;
293 SkConservativeClip fRasterClip;
294 SkMatrix fMatrix;
295 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296
Mike Reeda1361362017-03-07 09:37:29 -0500297 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700298 fFilter = nullptr;
299 fLayer = nullptr;
300 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800301 fMatrix.reset();
302 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700303
reedd9544982014-09-09 18:46:22 -0700304 // don't bother initializing fNext
305 inc_rec();
306 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400307 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700308 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700309 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700310 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800311 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700312
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 // don't bother initializing fNext
314 inc_rec();
315 }
316 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000317 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700318 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000319 dec_rec();
320 }
mtkleinfeaadee2015-04-08 11:25:48 -0700321
322 void reset(const SkIRect& bounds) {
323 SkASSERT(fLayer);
324 SkASSERT(fDeferredSaveCount == 0);
325
326 fMatrix.reset();
327 fRasterClip.setRect(bounds);
328 fLayer->reset(bounds);
329 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330};
331
Mike Reeda1361362017-03-07 09:37:29 -0500332class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333public:
Mike Reeda1361362017-03-07 09:37:29 -0500334 SkDrawIter(SkCanvas* canvas)
335 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
336 {}
reed@google.com4b226022011-01-11 18:32:13 +0000337
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000339 const DeviceCM* rec = fCurrLayer;
340 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400341 fDevice = rec->fDevice.get();
342 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700344 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 return true;
346 }
347 return false;
348 }
reed@google.com4b226022011-01-11 18:32:13 +0000349
reed@google.com6f8f2922011-03-04 22:27:10 +0000350 int getX() const { return fDevice->getOrigin().x(); }
351 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000353
Mike Reed99330ba2017-02-22 11:01:08 -0500354 SkBaseDevice* fDevice;
355
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 const DeviceCM* fCurrLayer;
358 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359};
360
Florin Malita713b8ef2017-04-28 10:57:24 -0400361#define FOR_EACH_TOP_DEVICE( code ) \
362 do { \
363 DeviceCM* layer = fMCRec->fTopLayer; \
364 while (layer) { \
365 SkBaseDevice* device = layer->fDevice.get(); \
366 if (device) { \
367 code; \
368 } \
369 layer = layer->fNext; \
370 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500371 } while (0)
372
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373/////////////////////////////////////////////////////////////////////////////
374
reeddbc3cef2015-04-29 12:18:57 -0700375static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
376 return lazy->isValid() ? lazy->get() : lazy->set(orig);
377}
378
379/**
380 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700381 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700382 */
reedd053ce92016-03-22 10:17:23 -0700383static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700384 SkImageFilter* imgf = paint.getImageFilter();
385 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700386 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700387 }
388
reedd053ce92016-03-22 10:17:23 -0700389 SkColorFilter* imgCFPtr;
390 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700391 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700392 }
reedd053ce92016-03-22 10:17:23 -0700393 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700394
395 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700396 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700397 // there is no existing paint colorfilter, so we can just return the imagefilter's
398 return imgCF;
399 }
400
401 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
402 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700403 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700404}
405
senorblanco87e066e2015-10-28 11:23:36 -0700406/**
407 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
408 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
409 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
410 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
411 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
412 * conservative "effective" bounds based on the settings in the paint... with one exception. This
413 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
414 * deliberately ignored.
415 */
416static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
417 const SkRect& rawBounds,
418 SkRect* storage) {
419 SkPaint tmpUnfiltered(paint);
420 tmpUnfiltered.setImageFilter(nullptr);
421 if (tmpUnfiltered.canComputeFastBounds()) {
422 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
423 } else {
424 return rawBounds;
425 }
426}
427
reed@android.com8a1c16f2008-12-17 15:59:43 +0000428class AutoDrawLooper {
429public:
senorblanco87e066e2015-10-28 11:23:36 -0700430 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
431 // paint. It's used to determine the size of the offscreen layer for filters.
432 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700433 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700434 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000435 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800436#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800438#else
439 fFilter = nullptr;
440#endif
reed4a8126e2014-09-22 07:29:03 -0700441 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000442 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700443 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000444 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445
reedd053ce92016-03-22 10:17:23 -0700446 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700447 if (simplifiedCF) {
448 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700449 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700450 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700451 fPaint = paint;
452 }
453
454 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700455 /**
456 * We implement ImageFilters for a given draw by creating a layer, then applying the
457 * imagefilter to the pixels of that layer (its backing surface/image), and then
458 * we call restore() to xfer that layer to the main canvas.
459 *
460 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
461 * 2. Generate the src pixels:
462 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
463 * return (fPaint). We then draw the primitive (using srcover) into a cleared
464 * buffer/surface.
465 * 3. Restore the layer created in #1
466 * The imagefilter is passed the buffer/surface from the layer (now filled with the
467 * src pixels of the primitive). It returns a new "filtered" buffer, which we
468 * draw onto the previous layer using the xfermode from the original paint.
469 */
reed@google.com8926b162012-03-23 15:36:36 +0000470 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500471 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700472 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700473 SkRect storage;
474 if (rawBounds) {
475 // Make rawBounds include all paint outsets except for those due to image filters.
476 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
477 }
reedbfd5f172016-01-07 11:28:08 -0800478 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700479 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700480 fTempLayerForImageFilter = true;
481 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000482 }
483
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000484 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500485 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000486 fIsSimple = false;
487 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700488 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000489 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700490 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000491 }
492 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000493
reed@android.com8a1c16f2008-12-17 15:59:43 +0000494 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700495 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000496 fCanvas->internalRestore();
497 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000498 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000499 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000500
reed@google.com4e2b3d32011-04-07 14:18:59 +0000501 const SkPaint& paint() const {
502 SkASSERT(fPaint);
503 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000504 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000505
reed@google.com129ec222012-05-15 13:24:09 +0000506 bool next(SkDrawFilter::Type drawType) {
507 if (fDone) {
508 return false;
509 } else if (fIsSimple) {
510 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000511 return !fPaint->nothingToDraw();
512 } else {
513 return this->doNext(drawType);
514 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000515 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000516
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500518 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700519 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000520 SkCanvas* fCanvas;
521 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000522 SkDrawFilter* fFilter;
523 const SkPaint* fPaint;
524 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700525 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000526 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000527 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000528 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500529 char fStorage[48];
530 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000531
532 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000533};
534
reed@google.com129ec222012-05-15 13:24:09 +0000535bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700536 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000537 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700538 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000539
reeddbc3cef2015-04-29 12:18:57 -0700540 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
541 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000542
reed5c476fb2015-04-20 08:04:21 -0700543 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700544 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700545 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000546 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000547
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000548 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000549 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000550 return false;
551 }
552 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000553 if (!fFilter->filter(paint, drawType)) {
554 fDone = true;
555 return false;
556 }
halcanary96fcdcc2015-08-27 07:41:13 -0700557 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000558 // no looper means we only draw once
559 fDone = true;
560 }
561 }
562 fPaint = paint;
563
564 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000565 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000566 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000567 }
568
569 // call this after any possible paint modifiers
570 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700571 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000572 return false;
573 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000574 return true;
575}
576
reed@android.com8a1c16f2008-12-17 15:59:43 +0000577////////// macros to place around the internal draw calls //////////////////
578
reed3aafe112016-08-18 12:45:34 -0700579#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
580 this->predrawNotify(); \
581 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
582 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800583 SkDrawIter iter(this);
584
585
reed@google.com8926b162012-03-23 15:36:36 +0000586#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000587 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700588 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000589 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000590 SkDrawIter iter(this);
591
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000592#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000593 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700594 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000595 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000596 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000597
reedc83a2972015-07-16 07:40:45 -0700598#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
599 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700600 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700601 while (looper.next(type)) { \
602 SkDrawIter iter(this);
603
reed@google.com4e2b3d32011-04-07 14:18:59 +0000604#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000605
606////////////////////////////////////////////////////////////////////////////
607
msarettfbfa2582016-08-12 08:29:08 -0700608static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
609 if (bounds.isEmpty()) {
610 return SkRect::MakeEmpty();
611 }
612
613 // Expand bounds out by 1 in case we are anti-aliasing. We store the
614 // bounds as floats to enable a faster quick reject implementation.
615 SkRect dst;
616 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
617 return dst;
618}
619
mtkleinfeaadee2015-04-08 11:25:48 -0700620void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
621 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700622 fMCRec->reset(bounds);
623
624 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500625 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400626 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700627 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700628 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700629}
630
reedd9544982014-09-09 18:46:22 -0700631SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800632 if (device && device->forceConservativeRasterClip()) {
633 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
634 }
reed42b73eb2015-11-20 13:42:42 -0800635
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000636 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800637 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700638 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000639
640 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500641 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500642 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700643 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644
reeda499f902015-05-01 09:34:31 -0700645 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
646 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400647 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700648
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000650
halcanary96fcdcc2015-08-27 07:41:13 -0700651 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000652
reedf92c8662014-08-18 08:02:43 -0700653 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700654 // The root device and the canvas should always have the same pixel geometry
655 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800656 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700657 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500658
Mike Reedc42a1cd2017-02-14 14:25:14 -0500659 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700660 }
msarettfbfa2582016-08-12 08:29:08 -0700661
reedf92c8662014-08-18 08:02:43 -0700662 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663}
664
reed@google.comcde92112011-07-06 20:00:52 +0000665SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000666 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700667 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000668{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000669 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000670
halcanary96fcdcc2015-08-27 07:41:13 -0700671 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000672}
673
reed96a857e2015-01-25 10:33:58 -0800674SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000675 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800676 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000677{
678 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700679
Mike Reed566e53c2017-03-10 10:49:45 -0500680 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700681 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700682}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000683
reed78e27682014-11-19 08:04:34 -0800684SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700685 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700686 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700687{
688 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700689
Mike Reed566e53c2017-03-10 10:49:45 -0500690 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
691 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700692}
693
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000694SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000695 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700696 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000697{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000698 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700699
reedd9544982014-09-09 18:46:22 -0700700 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000701}
702
robertphillipsfcf78292015-06-19 11:49:52 -0700703SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
704 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700705 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700706{
707 inc_canvas();
708
709 this->init(device, flags);
710}
711
reed4a8126e2014-09-22 07:29:03 -0700712SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700713 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700714 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700715{
716 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700717
Hal Canary704cd322016-11-07 14:13:52 -0500718 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
719 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700720}
reed29c857d2014-09-21 10:25:07 -0700721
Mike Reed356f7c22017-01-10 11:58:39 -0500722SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
723 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700724 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
725 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500726 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700727{
728 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700729
Mike Reed356f7c22017-01-10 11:58:39 -0500730 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500731 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732}
733
Mike Reed356f7c22017-01-10 11:58:39 -0500734SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
735
Matt Sarett31f99ce2017-04-11 08:46:01 -0400736#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
737SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
738 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
739 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
740 , fAllocator(nullptr)
741{
742 inc_canvas();
743
744 SkBitmap tmp(bitmap);
745 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
746 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
747 this->init(device.get(), kDefault_InitFlags);
748}
749#endif
750
reed@android.com8a1c16f2008-12-17 15:59:43 +0000751SkCanvas::~SkCanvas() {
752 // free up the contents of our deque
753 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000754
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755 this->internalRestore(); // restore the last, since we're going away
756
halcanary385fe4d2015-08-26 13:07:48 -0700757 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000758
reed@android.com8a1c16f2008-12-17 15:59:43 +0000759 dec_canvas();
760}
761
fmalita53d9f1c2016-01-25 06:23:54 -0800762#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763SkDrawFilter* SkCanvas::getDrawFilter() const {
764 return fMCRec->fFilter;
765}
766
767SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700768 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
770 return filter;
771}
fmalita77650002016-01-21 18:47:11 -0800772#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000774SkMetaData& SkCanvas::getMetaData() {
775 // metadata users are rare, so we lazily allocate it. If that changes we
776 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700777 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000778 fMetaData = new SkMetaData;
779 }
780 return *fMetaData;
781}
782
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783///////////////////////////////////////////////////////////////////////////////
784
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000785void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700786 this->onFlush();
787}
788
789void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000790 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000791 if (device) {
792 device->flush();
793 }
794}
795
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000796SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000797 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000798 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
799}
800
senorblancoafc7cce2016-02-02 18:44:15 -0800801SkIRect SkCanvas::getTopLayerBounds() const {
802 SkBaseDevice* d = this->getTopDevice();
803 if (!d) {
804 return SkIRect::MakeEmpty();
805 }
806 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
807}
808
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000809SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000811 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400813 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000814}
815
Florin Malita0ed3b642017-01-13 16:56:38 +0000816SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400817 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000818}
819
reed96472de2014-12-10 09:53:42 -0800820bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000821 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000822 if (!device) {
823 return false;
824 }
mtkleinf0f14112014-12-12 08:46:25 -0800825
Matt Sarett03dd6d52017-01-23 12:15:09 -0500826 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000827}
828
Mike Reed12e946b2017-04-17 10:53:29 -0400829bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
830 return pm.addr() && this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y);
831}
832
833bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
834 SkPixmap pm;
835 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
836}
837
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000838bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400839 SkPixmap pm;
840 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700841 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000842 }
843 return false;
844}
845
Matt Sarett03dd6d52017-01-23 12:15:09 -0500846bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000847 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000848 SkBaseDevice* device = this->getDevice();
849 if (!device) {
850 return false;
851 }
852
Matt Sarett03dd6d52017-01-23 12:15:09 -0500853 // This check gives us an early out and prevents generation ID churn on the surface.
854 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
855 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
856 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
857 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000858 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000859
Matt Sarett03dd6d52017-01-23 12:15:09 -0500860 // Tell our owning surface to bump its generation ID.
861 const bool completeOverwrite =
862 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700863 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700864
Matt Sarett03dd6d52017-01-23 12:15:09 -0500865 // This can still fail, most notably in the case of a invalid color type or alpha type
866 // conversion. We could pull those checks into this function and avoid the unnecessary
867 // generation ID bump. But then we would be performing those checks twice, since they
868 // are also necessary at the bitmap/pixmap entry points.
869 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000870}
reed@google.com51df9e32010-12-23 19:29:18 +0000871
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872//////////////////////////////////////////////////////////////////////////////
873
reed2ff1fce2014-12-11 07:07:37 -0800874void SkCanvas::checkForDeferredSave() {
875 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800876 this->doSave();
877 }
878}
879
reedf0090cb2014-11-26 08:55:51 -0800880int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800881#ifdef SK_DEBUG
882 int count = 0;
883 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
884 for (;;) {
885 const MCRec* rec = (const MCRec*)iter.next();
886 if (!rec) {
887 break;
888 }
889 count += 1 + rec->fDeferredSaveCount;
890 }
891 SkASSERT(count == fSaveCount);
892#endif
893 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800894}
895
896int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800897 fSaveCount += 1;
898 fMCRec->fDeferredSaveCount += 1;
899 return this->getSaveCount() - 1; // return our prev value
900}
901
902void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800903 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700904
905 SkASSERT(fMCRec->fDeferredSaveCount > 0);
906 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800907 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800908}
909
910void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800911 if (fMCRec->fDeferredSaveCount > 0) {
912 SkASSERT(fSaveCount > 1);
913 fSaveCount -= 1;
914 fMCRec->fDeferredSaveCount -= 1;
915 } else {
916 // check for underflow
917 if (fMCStack.count() > 1) {
918 this->willRestore();
919 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700920 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800921 this->internalRestore();
922 this->didRestore();
923 }
reedf0090cb2014-11-26 08:55:51 -0800924 }
925}
926
927void SkCanvas::restoreToCount(int count) {
928 // sanity check
929 if (count < 1) {
930 count = 1;
931 }
mtkleinf0f14112014-12-12 08:46:25 -0800932
reedf0090cb2014-11-26 08:55:51 -0800933 int n = this->getSaveCount() - count;
934 for (int i = 0; i < n; ++i) {
935 this->restore();
936 }
937}
938
reed2ff1fce2014-12-11 07:07:37 -0800939void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000940 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700941 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000942 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000943
Mike Reedc42a1cd2017-02-14 14:25:14 -0500944 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945}
946
reed4960eee2015-12-18 07:09:18 -0800947bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800948 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949}
950
reed4960eee2015-12-18 07:09:18 -0800951bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700952 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500953 SkIRect clipBounds = this->getDeviceClipBounds();
954 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000955 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000956 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000957
reed96e657d2015-03-10 17:30:07 -0700958 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
959
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000960 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700961 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800962 if (bounds && !imageFilter->canComputeFastBounds()) {
963 bounds = nullptr;
964 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000965 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000966 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700967 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000969
reed96e657d2015-03-10 17:30:07 -0700970 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971 r.roundOut(&ir);
972 // early exit if the layer's bounds are clipped out
973 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800974 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500975 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700976 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700977 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000978 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000979 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980 }
981 } else { // no user bounds, so just use the clip
982 ir = clipBounds;
983 }
reed180aec42015-03-11 10:39:04 -0700984 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000985
reed4960eee2015-12-18 07:09:18 -0800986 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700987 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700988 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700989 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000990 }
991
992 if (intersection) {
993 *intersection = ir;
994 }
995 return true;
996}
997
reed4960eee2015-12-18 07:09:18 -0800998
reed4960eee2015-12-18 07:09:18 -0800999int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1000 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001001}
1002
reed70ee31b2015-12-10 13:44:45 -08001003int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001004 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1005}
1006
1007int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001008 SkTCopyOnFirstWrite<SaveLayerRec> rec(origRec);
reed4960eee2015-12-18 07:09:18 -08001009 if (gIgnoreSaveLayerBounds) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001010 rec.writable()->fBounds = nullptr;
reed4960eee2015-12-18 07:09:18 -08001011 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001012
1013 SaveLayerStrategy strategy = this->getSaveLayerStrategy(*rec);
reed4960eee2015-12-18 07:09:18 -08001014 fSaveCount += 1;
Florin Malita53f77bd2017-04-28 13:48:37 -04001015 this->internalSaveLayer(*rec, strategy);
reed4960eee2015-12-18 07:09:18 -08001016 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001017}
1018
reeda2217ef2016-07-20 06:04:34 -07001019void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001020 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001021 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001022 SkDraw draw;
1023 SkRasterClip rc;
1024 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1025 if (!dst->accessPixels(&draw.fDst)) {
1026 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001027 }
reeda2217ef2016-07-20 06:04:34 -07001028 draw.fMatrix = &SkMatrix::I();
1029 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001030
1031 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001032 if (filter) {
1033 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1034 }
reeda2217ef2016-07-20 06:04:34 -07001035
Mike Reedc42a1cd2017-02-14 14:25:14 -05001036 int x = src->getOrigin().x() - dstOrigin.x();
1037 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001038 auto special = src->snapSpecial();
1039 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001040 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -07001041 }
robertphillips7354a4b2015-12-16 05:08:27 -08001042}
reed70ee31b2015-12-10 13:44:45 -08001043
reed129ed1c2016-02-22 06:42:31 -08001044static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1045 const SkPaint* paint) {
1046 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1047 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001048 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001049 const bool hasImageFilter = paint && paint->getImageFilter();
1050
1051 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1052 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1053 // force to L32
1054 return SkImageInfo::MakeN32(w, h, alphaType);
1055 } else {
1056 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001057 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001058 }
1059}
1060
reed4960eee2015-12-18 07:09:18 -08001061void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1062 const SkRect* bounds = rec.fBounds;
1063 const SkPaint* paint = rec.fPaint;
1064 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1065
reed8c30a812016-04-20 16:36:51 -07001066 SkLazyPaint lazyP;
1067 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1068 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001069 SkMatrix remainder;
1070 SkSize scale;
1071 /*
1072 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1073 * but they do handle scaling. To accommodate this, we do the following:
1074 *
1075 * 1. Stash off the current CTM
1076 * 2. Decompose the CTM into SCALE and REMAINDER
1077 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1078 * contains the REMAINDER
1079 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1080 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1081 * of the original imagefilter, and draw that (via drawSprite)
1082 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1083 *
1084 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1085 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1086 */
reed96a04f32016-04-25 09:25:15 -07001087 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001088 stashedMatrix.decomposeScale(&scale, &remainder))
1089 {
1090 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1091 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1092 SkPaint* p = lazyP.set(*paint);
1093 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1094 SkFilterQuality::kLow_SkFilterQuality,
1095 sk_ref_sp(imageFilter)));
1096 imageFilter = p->getImageFilter();
1097 paint = p;
1098 }
reed8c30a812016-04-20 16:36:51 -07001099
junov@chromium.orga907ac32012-02-24 21:54:07 +00001100 // do this before we create the layer. We don't call the public save() since
1101 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001102 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001103
junov@chromium.orga907ac32012-02-24 21:54:07 +00001104 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001105 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001106 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107 }
1108
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001109 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1110 // the clipRectBounds() call above?
1111 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001112 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001113 }
1114
reed4960eee2015-12-18 07:09:18 -08001115 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001116 SkPixelGeometry geo = fProps.pixelGeometry();
1117 if (paint) {
reed76033be2015-03-14 10:54:31 -07001118 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001119 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001120 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001121 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001122 }
1123 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001124
robertphillips5139e502016-07-19 05:10:40 -07001125 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001126 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001127 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001128 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001129 }
reedb2db8982014-11-13 12:41:02 -08001130
robertphillips5139e502016-07-19 05:10:40 -07001131 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001132 paint);
1133
Hal Canary704cd322016-11-07 14:13:52 -05001134 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001135 {
reed70ee31b2015-12-10 13:44:45 -08001136 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001137 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001138 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001139 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001140 preserveLCDText,
1141 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001142 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1143 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001144 return;
reed61f501f2015-04-29 08:34:00 -07001145 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001146 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001147 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001148
Mike Reedb43a3e02017-02-11 10:18:58 -05001149 // only have a "next" if this new layer doesn't affect the clip (rare)
1150 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151 fMCRec->fLayer = layer;
1152 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001153
Mike Reedc61abee2017-02-28 17:45:27 -05001154 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001155 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001156 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001157 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001158
Mike Reedc42a1cd2017-02-14 14:25:14 -05001159 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1160
1161 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1162 if (layer->fNext) {
1163 // need to punch a hole in the previous device, so we don't draw there, given that
1164 // the new top-layer will allow drawing to happen "below" it.
1165 SkRegion hole(ir);
1166 do {
1167 layer = layer->fNext;
1168 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1169 } while (layer->fNext);
1170 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001171}
1172
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001173int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001174 if (0xFF == alpha) {
1175 return this->saveLayer(bounds, nullptr);
1176 } else {
1177 SkPaint tmpPaint;
1178 tmpPaint.setAlpha(alpha);
1179 return this->saveLayer(bounds, &tmpPaint);
1180 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001181}
1182
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183void SkCanvas::internalRestore() {
1184 SkASSERT(fMCStack.count() != 0);
1185
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001186 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001187 DeviceCM* layer = fMCRec->fLayer; // may be null
1188 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001189 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001190
1191 // now do the normal restore()
1192 fMCRec->~MCRec(); // balanced in save()
1193 fMCStack.pop_back();
1194 fMCRec = (MCRec*)fMCStack.back();
1195
Mike Reedc42a1cd2017-02-14 14:25:14 -05001196 if (fMCRec) {
1197 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1198 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001199
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1201 since if we're being recorded, we don't want to record this (the
1202 recorder will have already recorded the restore).
1203 */
bsalomon49f085d2014-09-05 13:34:00 -07001204 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001205 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001206 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001207 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001208 layer->fPaint.get(),
1209 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001210 // restore what we smashed in internalSaveLayer
1211 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001212 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001213 delete layer;
reedb679ca82015-04-07 04:40:48 -07001214 } else {
1215 // we're at the root
reeda499f902015-05-01 09:34:31 -07001216 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001217 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001218 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001219 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001220 }
msarettfbfa2582016-08-12 08:29:08 -07001221
1222 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001223 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001224 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1225 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226}
1227
reede8f30622016-03-23 18:59:25 -07001228sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001229 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001230 props = &fProps;
1231 }
1232 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001233}
1234
reede8f30622016-03-23 18:59:25 -07001235sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001236 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001237 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001238}
1239
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001240SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001241 return this->onImageInfo();
1242}
1243
1244SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001245 SkBaseDevice* dev = this->getDevice();
1246 if (dev) {
1247 return dev->imageInfo();
1248 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001249 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001250 }
1251}
1252
brianosman898235c2016-04-06 07:38:23 -07001253bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001254 return this->onGetProps(props);
1255}
1256
1257bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001258 SkBaseDevice* dev = this->getDevice();
1259 if (dev) {
1260 if (props) {
1261 *props = fProps;
1262 }
1263 return true;
1264 } else {
1265 return false;
1266 }
1267}
1268
reed6ceeebd2016-03-09 14:26:26 -08001269bool SkCanvas::peekPixels(SkPixmap* pmap) {
1270 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001271}
1272
reed884e97c2015-05-26 11:31:54 -07001273bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001274 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001275 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001276}
1277
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001278void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001279 SkPixmap pmap;
1280 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001281 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001282 }
1283 if (info) {
1284 *info = pmap.info();
1285 }
1286 if (rowBytes) {
1287 *rowBytes = pmap.rowBytes();
1288 }
1289 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001290 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001291 }
reed884e97c2015-05-26 11:31:54 -07001292 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001293}
1294
reed884e97c2015-05-26 11:31:54 -07001295bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001296 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001297 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001298}
1299
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301
Florin Malita53f77bd2017-04-28 13:48:37 -04001302void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1303 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001304 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001305 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306 paint = &tmp;
1307 }
reed@google.com4b226022011-01-11 18:32:13 +00001308
reed@google.com8926b162012-03-23 15:36:36 +00001309 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001310
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001312 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001313 paint = &looper.paint();
1314 SkImageFilter* filter = paint->getImageFilter();
1315 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001316 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001317 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1318 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001319 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1320 clipImage, clipMatrix);
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
1401//////////////////////////////////////////////////////////////////////////////
1402
Mike Reedc1f77742016-12-09 09:00:50 -05001403void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001404 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001405 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1406 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001407}
1408
Mike Reedc1f77742016-12-09 09:00:50 -05001409void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001410 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001411
Mike Reed7627fa52017-02-08 10:07:53 -05001412 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001413
reedc64eff52015-11-21 12:39:45 -08001414 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001415 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1416 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001417 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418}
1419
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001420void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1421 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001422 if (fClipRestrictionRect.isEmpty()) {
1423 // we notify the device, but we *dont* resolve deferred saves (since we're just
1424 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001425 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001426 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001427 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001428 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001429 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001430 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001431 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1432 }
1433}
1434
Mike Reedc1f77742016-12-09 09:00:50 -05001435void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001436 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001438 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001439 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1440 } else {
1441 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001442 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001443}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001444
Mike Reedc1f77742016-12-09 09:00:50 -05001445void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001446 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001447
Brian Salomona3b45d42016-10-03 11:36:16 -04001448 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001449
Mike Reed7627fa52017-02-08 10:07:53 -05001450 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001451
Brian Salomona3b45d42016-10-03 11:36:16 -04001452 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1453 isAA);
1454 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001455}
1456
Mike Reedc1f77742016-12-09 09:00:50 -05001457void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001458 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001459 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001460
1461 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1462 SkRect r;
1463 if (path.isRect(&r)) {
1464 this->onClipRect(r, op, edgeStyle);
1465 return;
1466 }
1467 SkRRect rrect;
1468 if (path.isOval(&r)) {
1469 rrect.setOval(r);
1470 this->onClipRRect(rrect, op, edgeStyle);
1471 return;
1472 }
1473 if (path.isRRect(&rrect)) {
1474 this->onClipRRect(rrect, op, edgeStyle);
1475 return;
1476 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001477 }
robertphillips39f05382015-11-24 09:30:12 -08001478
1479 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001480}
1481
Mike Reedc1f77742016-12-09 09:00:50 -05001482void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001483 AutoValidateClip avc(this);
1484
Brian Salomona3b45d42016-10-03 11:36:16 -04001485 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001486
Mike Reed7627fa52017-02-08 10:07:53 -05001487 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488
Brian Salomona3b45d42016-10-03 11:36:16 -04001489 const SkPath* rasterClipPath = &path;
1490 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001491 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1492 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001493 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001494}
1495
Mike Reedc1f77742016-12-09 09:00:50 -05001496void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001497 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001498 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001499}
1500
Mike Reedc1f77742016-12-09 09:00:50 -05001501void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001502 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001503
reed@google.com5c3d1472011-02-22 19:12:23 +00001504 AutoValidateClip avc(this);
1505
reed73603f32016-09-20 08:42:38 -07001506 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001507 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508}
1509
reed@google.com819c9212011-02-23 18:56:55 +00001510#ifdef SK_DEBUG
1511void SkCanvas::validateClip() const {
1512 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001513 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001514 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001515 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001516 return;
1517 }
reed@google.com819c9212011-02-23 18:56:55 +00001518}
1519#endif
1520
Mike Reeda1361362017-03-07 09:37:29 -05001521bool SkCanvas::androidFramework_isClipAA() const {
1522 bool containsAA = false;
1523
1524 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1525
1526 return containsAA;
1527}
1528
1529class RgnAccumulator {
1530 SkRegion* fRgn;
1531public:
1532 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1533 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1534 SkIPoint origin = device->getOrigin();
1535 if (origin.x() | origin.y()) {
1536 rgn->translate(origin.x(), origin.y());
1537 }
1538 fRgn->op(*rgn, SkRegion::kUnion_Op);
1539 }
1540};
1541
1542void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1543 RgnAccumulator accum(rgn);
1544 SkRegion tmp;
1545
1546 rgn->setEmpty();
1547 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001548}
1549
reed@google.com5c3d1472011-02-22 19:12:23 +00001550///////////////////////////////////////////////////////////////////////////////
1551
reed@google.com754de5f2014-02-24 19:38:20 +00001552bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001553 return fMCRec->fRasterClip.isEmpty();
1554
1555 // TODO: should we only use the conservative answer in a recording canvas?
1556#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001557 SkBaseDevice* dev = this->getTopDevice();
1558 // if no device we return true
1559 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001560#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001561}
1562
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001563bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001564 SkBaseDevice* dev = this->getTopDevice();
1565 // if no device we return false
1566 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001567}
1568
msarettfbfa2582016-08-12 08:29:08 -07001569static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1570#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1571 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1572 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1573 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1574 return 0xF != _mm_movemask_ps(mask);
1575#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1576 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1577 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1578 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1579 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1580#else
1581 SkRect devRectAsRect;
1582 SkRect devClipAsRect;
1583 devRect.store(&devRectAsRect.fLeft);
1584 devClip.store(&devClipAsRect.fLeft);
1585 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1586#endif
1587}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001588
msarettfbfa2582016-08-12 08:29:08 -07001589// It's important for this function to not be inlined. Otherwise the compiler will share code
1590// between the fast path and the slow path, resulting in two slow paths.
1591static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1592 const SkMatrix& matrix) {
1593 SkRect deviceRect;
1594 matrix.mapRect(&deviceRect, src);
1595 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1596}
1597
1598bool SkCanvas::quickReject(const SkRect& src) const {
1599#ifdef SK_DEBUG
1600 // Verify that fDeviceClipBounds are set properly.
1601 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001602 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001603 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001604 } else {
msarettfbfa2582016-08-12 08:29:08 -07001605 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001606 }
msarettfbfa2582016-08-12 08:29:08 -07001607
msarett9637ea92016-08-18 14:03:30 -07001608 // Verify that fIsScaleTranslate is set properly.
1609 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001610#endif
1611
msarett9637ea92016-08-18 14:03:30 -07001612 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001613 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1614 }
1615
1616 // We inline the implementation of mapScaleTranslate() for the fast path.
1617 float sx = fMCRec->fMatrix.getScaleX();
1618 float sy = fMCRec->fMatrix.getScaleY();
1619 float tx = fMCRec->fMatrix.getTranslateX();
1620 float ty = fMCRec->fMatrix.getTranslateY();
1621 Sk4f scale(sx, sy, sx, sy);
1622 Sk4f trans(tx, ty, tx, ty);
1623
1624 // Apply matrix.
1625 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1626
1627 // Make sure left < right, top < bottom.
1628 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1629 Sk4f min = Sk4f::Min(ltrb, rblt);
1630 Sk4f max = Sk4f::Max(ltrb, rblt);
1631 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1632 // ARM this sequence generates the fastest (a single instruction).
1633 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1634
1635 // Check if the device rect is NaN or outside the clip.
1636 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001637}
1638
reed@google.com3b3e8952012-08-16 20:53:31 +00001639bool SkCanvas::quickReject(const SkPath& path) const {
1640 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641}
1642
Mike Reed42e8c532017-01-23 14:09:13 -05001643SkRect SkCanvas::onGetLocalClipBounds() const {
1644 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001645 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001646 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001647 }
1648
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001649 SkMatrix inverse;
1650 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001651 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001652 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001653 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001654
Mike Reed42e8c532017-01-23 14:09:13 -05001655 SkRect bounds;
1656 SkRect r;
1657 // adjust it outwards in case we are antialiasing
1658 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001659
Mike Reed42e8c532017-01-23 14:09:13 -05001660 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1661 ibounds.fRight + inset, ibounds.fBottom + inset);
1662 inverse.mapRect(&bounds, r);
1663 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664}
1665
Mike Reed42e8c532017-01-23 14:09:13 -05001666SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001667 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001668}
1669
reed@android.com8a1c16f2008-12-17 15:59:43 +00001670const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001671 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001672}
1673
Brian Osman11052242016-10-27 14:47:55 -04001674GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001675 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001676 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001677}
1678
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001679GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001680 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001681 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001682}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001683
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001684void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1685 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001686 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001687 if (outer.isEmpty()) {
1688 return;
1689 }
1690 if (inner.isEmpty()) {
1691 this->drawRRect(outer, paint);
1692 return;
1693 }
1694
1695 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001696 // be able to return ...
1697 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001698 //
1699 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001700 if (!outer.getBounds().contains(inner.getBounds())) {
1701 return;
1702 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001703
1704 this->onDrawDRRect(outer, inner, paint);
1705}
1706
reed41af9662015-01-05 07:49:08 -08001707// These need to stop being virtual -- clients need to override the onDraw... versions
1708
1709void SkCanvas::drawPaint(const SkPaint& paint) {
1710 this->onDrawPaint(paint);
1711}
1712
1713void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001714 // To avoid redundant logic in our culling code and various backends, we always sort rects
1715 // before passing them along.
1716 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001717}
1718
msarettdca352e2016-08-26 06:37:45 -07001719void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1720 if (region.isEmpty()) {
1721 return;
1722 }
1723
1724 if (region.isRect()) {
1725 return this->drawIRect(region.getBounds(), paint);
1726 }
1727
1728 this->onDrawRegion(region, paint);
1729}
1730
reed41af9662015-01-05 07:49:08 -08001731void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001732 // To avoid redundant logic in our culling code and various backends, we always sort rects
1733 // before passing them along.
1734 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001735}
1736
1737void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1738 this->onDrawRRect(rrect, paint);
1739}
1740
1741void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1742 this->onDrawPoints(mode, count, pts, paint);
1743}
1744
Mike Reede88a1cb2017-03-17 09:50:46 -04001745void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1746 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001747 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001748 this->onDrawVerticesObject(vertices.get(), mode, paint);
1749}
1750
1751void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1752 RETURN_ON_NULL(vertices);
1753 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001754}
1755
1756void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1757 this->onDrawPath(path, paint);
1758}
1759
reeda85d4d02015-05-06 12:56:48 -07001760void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001761 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001762 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001763}
1764
reede47829b2015-08-06 10:02:53 -07001765void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1766 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001767 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001768 if (dst.isEmpty() || src.isEmpty()) {
1769 return;
1770 }
1771 this->onDrawImageRect(image, &src, dst, paint, constraint);
1772}
reed41af9662015-01-05 07:49:08 -08001773
reed84984ef2015-07-17 07:09:43 -07001774void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1775 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001776 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001777 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001778}
1779
reede47829b2015-08-06 10:02:53 -07001780void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1781 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001782 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001783 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1784 constraint);
1785}
reede47829b2015-08-06 10:02:53 -07001786
reed4c21dc52015-06-25 12:32:03 -07001787void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1788 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001789 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001790 if (dst.isEmpty()) {
1791 return;
1792 }
msarett552bca92016-08-03 06:53:26 -07001793 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1794 this->onDrawImageNine(image, center, dst, paint);
1795 } else {
reede47829b2015-08-06 10:02:53 -07001796 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001797 }
reed4c21dc52015-06-25 12:32:03 -07001798}
1799
msarett16882062016-08-16 09:31:08 -07001800void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1801 const SkPaint* paint) {
1802 RETURN_ON_NULL(image);
1803 if (dst.isEmpty()) {
1804 return;
1805 }
msarett71df2d72016-09-30 12:41:42 -07001806
1807 SkIRect bounds;
1808 Lattice latticePlusBounds = lattice;
1809 if (!latticePlusBounds.fBounds) {
1810 bounds = SkIRect::MakeWH(image->width(), image->height());
1811 latticePlusBounds.fBounds = &bounds;
1812 }
1813
1814 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1815 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001816 } else {
1817 this->drawImageRect(image, dst, paint);
1818 }
1819}
1820
reed41af9662015-01-05 07:49:08 -08001821void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001822 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001823 return;
1824 }
reed41af9662015-01-05 07:49:08 -08001825 this->onDrawBitmap(bitmap, dx, dy, paint);
1826}
1827
reede47829b2015-08-06 10:02:53 -07001828void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001829 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001830 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001831 return;
1832 }
reede47829b2015-08-06 10:02:53 -07001833 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001834}
1835
reed84984ef2015-07-17 07:09:43 -07001836void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1837 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001838 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001839}
1840
reede47829b2015-08-06 10:02:53 -07001841void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1842 SrcRectConstraint constraint) {
1843 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1844 constraint);
1845}
reede47829b2015-08-06 10:02:53 -07001846
reed41af9662015-01-05 07:49:08 -08001847void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1848 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001849 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001850 return;
1851 }
msarett552bca92016-08-03 06:53:26 -07001852 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1853 this->onDrawBitmapNine(bitmap, center, dst, paint);
1854 } else {
reeda5517e22015-07-14 10:54:12 -07001855 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001856 }
reed41af9662015-01-05 07:49:08 -08001857}
1858
msarettc573a402016-08-02 08:05:56 -07001859void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1860 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001861 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001862 return;
1863 }
msarett71df2d72016-09-30 12:41:42 -07001864
1865 SkIRect bounds;
1866 Lattice latticePlusBounds = lattice;
1867 if (!latticePlusBounds.fBounds) {
1868 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1869 latticePlusBounds.fBounds = &bounds;
1870 }
1871
1872 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1873 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001874 } else {
msarett16882062016-08-16 09:31:08 -07001875 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001876 }
msarettc573a402016-08-02 08:05:56 -07001877}
1878
reed71c3c762015-06-24 10:29:17 -07001879void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001880 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001881 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001882 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001883 if (count <= 0) {
1884 return;
1885 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001886 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001887 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001888 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001889}
1890
reedf70b5312016-03-04 16:36:20 -08001891void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1892 if (key) {
1893 this->onDrawAnnotation(rect, key, value);
1894 }
1895}
1896
reede47829b2015-08-06 10:02:53 -07001897void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1898 const SkPaint* paint, SrcRectConstraint constraint) {
1899 if (src) {
1900 this->drawImageRect(image, *src, dst, paint, constraint);
1901 } else {
1902 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1903 dst, paint, constraint);
1904 }
1905}
1906void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1907 const SkPaint* paint, SrcRectConstraint constraint) {
1908 if (src) {
1909 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1910 } else {
1911 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1912 dst, paint, constraint);
1913 }
1914}
1915
Mike Reed4204da22017-05-17 08:53:36 -04001916void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
1917 this->onDrawShadowRec(path, rec);
1918}
1919
1920void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1921 SkPaint paint;
1922 const SkRect& pathBounds = path.getBounds();
1923
1924 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1925 while (iter.next()) {
1926 iter.fDevice->drawShadow(path, rec);
1927 }
1928 LOOPER_END
1929}
1930
reed@android.com8a1c16f2008-12-17 15:59:43 +00001931//////////////////////////////////////////////////////////////////////////////
1932// These are the virtual drawing methods
1933//////////////////////////////////////////////////////////////////////////////
1934
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001935void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001936 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001937 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1938 }
1939}
1940
reed41af9662015-01-05 07:49:08 -08001941void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001942 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001943 this->internalDrawPaint(paint);
1944}
1945
1946void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001947 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001948
1949 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001950 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001951 }
1952
reed@google.com4e2b3d32011-04-07 14:18:59 +00001953 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001954}
1955
reed41af9662015-01-05 07:49:08 -08001956void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1957 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001958 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001959 if ((long)count <= 0) {
1960 return;
1961 }
1962
Mike Reed822128b2017-02-28 16:41:03 -05001963 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001964 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001965 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001966 // special-case 2 points (common for drawing a single line)
1967 if (2 == count) {
1968 r.set(pts[0], pts[1]);
1969 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001970 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001971 }
Mike Reed822128b2017-02-28 16:41:03 -05001972 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001973 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1974 return;
1975 }
1976 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001977 }
reed@google.coma584aed2012-05-16 14:06:02 +00001978
halcanary96fcdcc2015-08-27 07:41:13 -07001979 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001980
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001981 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001982
reed@android.com8a1c16f2008-12-17 15:59:43 +00001983 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001984 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001985 }
reed@google.com4b226022011-01-11 18:32:13 +00001986
reed@google.com4e2b3d32011-04-07 14:18:59 +00001987 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001988}
1989
reed4a167172016-08-18 17:15:25 -07001990static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1991 return ((intptr_t)paint.getImageFilter() |
1992#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1993 (intptr_t)canvas->getDrawFilter() |
1994#endif
1995 (intptr_t)paint.getLooper() ) != 0;
1996}
1997
reed41af9662015-01-05 07:49:08 -08001998void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001999 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
Brian Osman6e3ce402017-05-17 15:10:18 -04002000 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002001 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002002 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002003 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002004 return;
2005 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002006 }
reed@google.com4b226022011-01-11 18:32:13 +00002007
reed4a167172016-08-18 17:15:25 -07002008 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002009 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002010
reed4a167172016-08-18 17:15:25 -07002011 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002012 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002013 }
2014
2015 LOOPER_END
2016 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002017 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002018 SkDrawIter iter(this);
2019 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002020 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002021 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002022 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002023}
2024
msarett44df6512016-08-25 13:54:30 -07002025void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002026 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002027 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002028 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002029 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2030 return;
2031 }
msarett44df6512016-08-25 13:54:30 -07002032 }
2033
Mike Reed822128b2017-02-28 16:41:03 -05002034 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002035
2036 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002037 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002038 }
2039
2040 LOOPER_END
2041}
2042
reed41af9662015-01-05 07:49:08 -08002043void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002044 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
Brian Osman6e3ce402017-05-17 15:10:18 -04002045 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002046 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002047 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002048 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002049 return;
2050 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002051 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002052
Mike Reed822128b2017-02-28 16:41:03 -05002053 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002054
2055 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002056 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002057 }
2058
2059 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002060}
2061
bsalomonac3aa242016-08-19 11:25:19 -07002062void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2063 SkScalar sweepAngle, bool useCenter,
2064 const SkPaint& paint) {
2065 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
Brian Osman6e3ce402017-05-17 15:10:18 -04002066 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002067 if (paint.canComputeFastBounds()) {
2068 SkRect storage;
2069 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002070 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002071 return;
2072 }
bsalomonac3aa242016-08-19 11:25:19 -07002073 }
2074
Mike Reed822128b2017-02-28 16:41:03 -05002075 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002076
2077 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002078 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002079 }
2080
2081 LOOPER_END
2082}
2083
reed41af9662015-01-05 07:49:08 -08002084void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002085 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002086 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002087 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002088 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2089 return;
2090 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002091 }
2092
2093 if (rrect.isRect()) {
2094 // call the non-virtual version
2095 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002096 return;
2097 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002098 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002099 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2100 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002101 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002102
Mike Reed822128b2017-02-28 16:41:03 -05002103 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002104
2105 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002106 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002107 }
2108
2109 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002110}
2111
Mike Reed822128b2017-02-28 16:41:03 -05002112void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002113 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002114 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002115 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2116 return;
2117 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002118 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002119
Mike Reed822128b2017-02-28 16:41:03 -05002120 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002121
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002122 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002123 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002124 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002125
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002126 LOOPER_END
2127}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002128
reed41af9662015-01-05 07:49:08 -08002129void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002130 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002131 if (!path.isFinite()) {
2132 return;
2133 }
2134
Mike Reed822128b2017-02-28 16:41:03 -05002135 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002136 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002137 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002138 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2139 return;
2140 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002141 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002142
Mike Reed822128b2017-02-28 16:41:03 -05002143 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002144 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002145 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002146 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002147 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002148 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002149
Mike Reed822128b2017-02-28 16:41:03 -05002150 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151
2152 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002153 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002154 }
2155
reed@google.com4e2b3d32011-04-07 14:18:59 +00002156 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002157}
2158
reed262a71b2015-12-05 13:07:27 -08002159bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002160 if (!paint.getImageFilter()) {
2161 return false;
2162 }
2163
2164 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002165 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002166 return false;
2167 }
2168
2169 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2170 // Once we can filter and the filter will return a result larger than itself, we should be
2171 // able to remove this constraint.
2172 // skbug.com/4526
2173 //
2174 SkPoint pt;
2175 ctm.mapXY(x, y, &pt);
2176 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2177 return ir.contains(fMCRec->fRasterClip.getBounds());
2178}
2179
reeda85d4d02015-05-06 12:56:48 -07002180void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002181 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002182 SkRect bounds = SkRect::MakeXYWH(x, y,
2183 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002184 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002185 SkRect tmp = bounds;
2186 if (paint) {
2187 paint->computeFastBounds(tmp, &tmp);
2188 }
2189 if (this->quickReject(tmp)) {
2190 return;
2191 }
reeda85d4d02015-05-06 12:56:48 -07002192 }
halcanary9d524f22016-03-29 09:03:52 -07002193
reeda85d4d02015-05-06 12:56:48 -07002194 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002195 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002196 paint = lazy.init();
2197 }
reed262a71b2015-12-05 13:07:27 -08002198
reeda2217ef2016-07-20 06:04:34 -07002199 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002200 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2201 *paint);
2202 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002203 special = this->getDevice()->makeSpecial(image);
2204 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002205 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002206 }
2207 }
2208
reed262a71b2015-12-05 13:07:27 -08002209 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2210
reeda85d4d02015-05-06 12:56:48 -07002211 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002212 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002213 if (special) {
2214 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002215 iter.fDevice->ctm().mapXY(x, y, &pt);
2216 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002217 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002218 SkScalarRoundToInt(pt.fY), pnt,
2219 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002220 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002221 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002222 }
reeda85d4d02015-05-06 12:56:48 -07002223 }
halcanary9d524f22016-03-29 09:03:52 -07002224
reeda85d4d02015-05-06 12:56:48 -07002225 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002226}
2227
reed41af9662015-01-05 07:49:08 -08002228void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002229 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002230 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002231 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002232 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002233 if (paint) {
2234 paint->computeFastBounds(dst, &storage);
2235 }
2236 if (this->quickReject(storage)) {
2237 return;
2238 }
reeda85d4d02015-05-06 12:56:48 -07002239 }
2240 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002241 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002242 paint = lazy.init();
2243 }
halcanary9d524f22016-03-29 09:03:52 -07002244
senorblancoc41e7e12015-12-07 12:51:30 -08002245 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002246 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002247
reeda85d4d02015-05-06 12:56:48 -07002248 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002249 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002250 }
halcanary9d524f22016-03-29 09:03:52 -07002251
reeda85d4d02015-05-06 12:56:48 -07002252 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002253}
2254
reed41af9662015-01-05 07:49:08 -08002255void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002256 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002257 SkDEBUGCODE(bitmap.validate();)
2258
reed33366972015-10-08 09:22:02 -07002259 if (bitmap.drawsNothing()) {
2260 return;
2261 }
2262
2263 SkLazyPaint lazy;
2264 if (nullptr == paint) {
2265 paint = lazy.init();
2266 }
2267
Mike Reed822128b2017-02-28 16:41:03 -05002268 SkRect bounds;
2269 bitmap.getBounds(&bounds);
2270 bounds.offset(x, y);
2271 bool canFastBounds = paint->canComputeFastBounds();
2272 if (canFastBounds) {
2273 SkRect storage;
2274 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002275 return;
2276 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002277 }
reed@google.com4b226022011-01-11 18:32:13 +00002278
reeda2217ef2016-07-20 06:04:34 -07002279 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002280 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2281 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002282 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002283 special = this->getDevice()->makeSpecial(bitmap);
2284 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002285 drawAsSprite = false;
2286 }
2287 }
2288
Mike Reed822128b2017-02-28 16:41:03 -05002289 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2290
2291 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002292
2293 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002294 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002295 if (special) {
reed262a71b2015-12-05 13:07:27 -08002296 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002297 iter.fDevice->ctm().mapXY(x, y, &pt);
2298 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002299 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002300 SkScalarRoundToInt(pt.fY), pnt,
2301 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002302 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002303 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002304 }
reed33366972015-10-08 09:22:02 -07002305 }
msarettfbfa2582016-08-12 08:29:08 -07002306
reed33366972015-10-08 09:22:02 -07002307 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308}
2309
reed@google.com9987ec32011-09-07 11:57:52 +00002310// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002311void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002312 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002313 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002314 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315 return;
2316 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002317
halcanary96fcdcc2015-08-27 07:41:13 -07002318 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002319 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002320 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2321 return;
2322 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002323 }
reed@google.com3d608122011-11-21 15:16:16 +00002324
reed@google.com33535f32012-09-25 15:37:50 +00002325 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002326 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002327 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002329
senorblancoc41e7e12015-12-07 12:51:30 -08002330 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002331 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002332
reed@google.com33535f32012-09-25 15:37:50 +00002333 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002334 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002335 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002336
reed@google.com33535f32012-09-25 15:37:50 +00002337 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002338}
2339
reed41af9662015-01-05 07:49:08 -08002340void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002341 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002342 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002343 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002344 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002345}
2346
reed4c21dc52015-06-25 12:32:03 -07002347void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2348 const SkPaint* paint) {
2349 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002350
halcanary96fcdcc2015-08-27 07:41:13 -07002351 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002352 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002353 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2354 return;
2355 }
reed@google.com3d608122011-11-21 15:16:16 +00002356 }
halcanary9d524f22016-03-29 09:03:52 -07002357
reed4c21dc52015-06-25 12:32:03 -07002358 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002359 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002360 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002361 }
halcanary9d524f22016-03-29 09:03:52 -07002362
senorblancoc41e7e12015-12-07 12:51:30 -08002363 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002364
reed4c21dc52015-06-25 12:32:03 -07002365 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002366 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002367 }
halcanary9d524f22016-03-29 09:03:52 -07002368
reed4c21dc52015-06-25 12:32:03 -07002369 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002370}
2371
reed41af9662015-01-05 07:49:08 -08002372void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2373 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002374 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002375 SkDEBUGCODE(bitmap.validate();)
2376
halcanary96fcdcc2015-08-27 07:41:13 -07002377 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002378 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002379 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2380 return;
2381 }
reed4c21dc52015-06-25 12:32:03 -07002382 }
halcanary9d524f22016-03-29 09:03:52 -07002383
reed4c21dc52015-06-25 12:32:03 -07002384 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002385 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002386 paint = lazy.init();
2387 }
halcanary9d524f22016-03-29 09:03:52 -07002388
senorblancoc41e7e12015-12-07 12:51:30 -08002389 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002390
reed4c21dc52015-06-25 12:32:03 -07002391 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002392 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002393 }
halcanary9d524f22016-03-29 09:03:52 -07002394
reed4c21dc52015-06-25 12:32:03 -07002395 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002396}
2397
msarett16882062016-08-16 09:31:08 -07002398void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2399 const SkPaint* paint) {
2400 if (nullptr == paint || paint->canComputeFastBounds()) {
2401 SkRect storage;
2402 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2403 return;
2404 }
2405 }
2406
2407 SkLazyPaint lazy;
2408 if (nullptr == paint) {
2409 paint = lazy.init();
2410 }
2411
2412 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2413
2414 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002415 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002416 }
2417
2418 LOOPER_END
2419}
2420
2421void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2422 const SkRect& dst, const SkPaint* paint) {
2423 if (nullptr == paint || paint->canComputeFastBounds()) {
2424 SkRect storage;
2425 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2426 return;
2427 }
2428 }
2429
2430 SkLazyPaint lazy;
2431 if (nullptr == paint) {
2432 paint = lazy.init();
2433 }
2434
2435 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2436
2437 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002438 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002439 }
2440
2441 LOOPER_END
2442}
2443
reed@google.comf67e4cf2011-03-15 20:56:58 +00002444class SkDeviceFilteredPaint {
2445public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002446 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002447 uint32_t filteredFlags = device->filterTextFlags(paint);
2448 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002449 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002450 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002451 fPaint = newPaint;
2452 } else {
2453 fPaint = &paint;
2454 }
2455 }
2456
reed@google.comf67e4cf2011-03-15 20:56:58 +00002457 const SkPaint& paint() const { return *fPaint; }
2458
2459private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002460 const SkPaint* fPaint;
2461 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002462};
2463
reed@google.come0d9ce82014-04-23 04:00:17 +00002464void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2465 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002466 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002467
2468 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002469 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002470 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002471 }
2472
reed@google.com4e2b3d32011-04-07 14:18:59 +00002473 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474}
2475
reed@google.come0d9ce82014-04-23 04:00:17 +00002476void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2477 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002478 SkPoint textOffset = SkPoint::Make(0, 0);
2479
halcanary96fcdcc2015-08-27 07:41:13 -07002480 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002481
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002483 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002484 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002485 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002486 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002487
reed@google.com4e2b3d32011-04-07 14:18:59 +00002488 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002489}
2490
reed@google.come0d9ce82014-04-23 04:00:17 +00002491void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2492 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002493
2494 SkPoint textOffset = SkPoint::Make(0, constY);
2495
halcanary96fcdcc2015-08-27 07:41:13 -07002496 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002497
reed@android.com8a1c16f2008-12-17 15:59:43 +00002498 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002499 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002500 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002501 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002502 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002503
reed@google.com4e2b3d32011-04-07 14:18:59 +00002504 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002505}
2506
reed@google.come0d9ce82014-04-23 04:00:17 +00002507void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2508 const SkMatrix* matrix, const SkPaint& paint) {
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()) {
Mike Reeda1361362017-03-07 09:37:29 -05002512 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002513 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002514 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002515
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002516 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002517}
2518
reed45561a02016-07-07 12:47:17 -07002519void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2520 const SkRect* cullRect, const SkPaint& paint) {
2521 if (cullRect && this->quickReject(*cullRect)) {
2522 return;
2523 }
2524
2525 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2526
2527 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002528 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002529 }
2530
2531 LOOPER_END
2532}
2533
fmalita00d5c2c2014-08-21 08:53:26 -07002534void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2535 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002536
fmalita85d5eb92015-03-04 11:20:12 -08002537 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002538 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002539 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002540 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002541 SkRect tmp;
2542 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2543 return;
2544 }
2545 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002546 }
2547
fmalita024f9962015-03-03 19:08:17 -08002548 // We cannot filter in the looper as we normally do, because the paint is
2549 // incomplete at this point (text-related attributes are embedded within blob run paints).
2550 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002551 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002552
fmalita85d5eb92015-03-04 11:20:12 -08002553 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002554
fmalitaaa1b9122014-08-28 14:32:24 -07002555 while (iter.next()) {
2556 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002557 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002558 }
2559
fmalitaaa1b9122014-08-28 14:32:24 -07002560 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002561
2562 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002563}
2564
Cary Clark2a475ea2017-04-28 15:35:12 -04002565void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2566 this->drawText(string.c_str(), string.size(), x, y, paint);
2567}
2568
reed@google.come0d9ce82014-04-23 04:00:17 +00002569// These will become non-virtual, so they always call the (virtual) onDraw... method
2570void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2571 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002572 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002573 if (byteLength) {
2574 this->onDrawText(text, byteLength, x, y, paint);
2575 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002576}
2577void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2578 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002579 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002580 if (byteLength) {
2581 this->onDrawPosText(text, byteLength, pos, paint);
2582 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002583}
2584void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2585 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002586 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002587 if (byteLength) {
2588 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2589 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002590}
2591void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2592 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002593 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002594 if (byteLength) {
2595 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2596 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002597}
reed45561a02016-07-07 12:47:17 -07002598void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2599 const SkRect* cullRect, const SkPaint& paint) {
2600 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2601 if (byteLength) {
2602 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2603 }
2604}
fmalita00d5c2c2014-08-21 08:53:26 -07002605void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2606 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002607 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002608 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002609 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002610}
reed@google.come0d9ce82014-04-23 04:00:17 +00002611
Mike Reede88a1cb2017-03-17 09:50:46 -04002612void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2613 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002614 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2615 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2616
2617 while (iter.next()) {
2618 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002619 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002620 }
2621
2622 LOOPER_END
2623}
2624
dandovb3c9d1c2014-08-12 08:34:29 -07002625void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002626 const SkPoint texCoords[4], SkBlendMode bmode,
2627 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002628 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002629 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002630 return;
2631 }
mtklein6cfa73a2014-08-13 13:33:49 -07002632
Mike Reedfaba3712016-11-03 14:45:31 -04002633 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002634}
2635
2636void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002637 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002638 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002639 // Since a patch is always within the convex hull of the control points, we discard it when its
2640 // bounding rectangle is completely outside the current clip.
2641 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002642 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002643 if (this->quickReject(bounds)) {
2644 return;
2645 }
mtklein6cfa73a2014-08-13 13:33:49 -07002646
halcanary96fcdcc2015-08-27 07:41:13 -07002647 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002648
dandovecfff212014-08-04 10:02:00 -07002649 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002650 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002651 }
mtklein6cfa73a2014-08-13 13:33:49 -07002652
dandovecfff212014-08-04 10:02:00 -07002653 LOOPER_END
2654}
2655
reeda8db7282015-07-07 10:22:31 -07002656void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002657 RETURN_ON_NULL(dr);
2658 if (x || y) {
2659 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2660 this->onDrawDrawable(dr, &matrix);
2661 } else {
2662 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002663 }
2664}
2665
reeda8db7282015-07-07 10:22:31 -07002666void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002667 RETURN_ON_NULL(dr);
2668 if (matrix && matrix->isIdentity()) {
2669 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002670 }
reede3b38ce2016-01-08 09:18:44 -08002671 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002672}
2673
2674void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002675 // drawable bounds are no longer reliable (e.g. android displaylist)
2676 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002677 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002678}
2679
reed71c3c762015-06-24 10:29:17 -07002680void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002681 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002682 const SkRect* cull, const SkPaint* paint) {
2683 if (cull && this->quickReject(*cull)) {
2684 return;
2685 }
2686
2687 SkPaint pnt;
2688 if (paint) {
2689 pnt = *paint;
2690 }
halcanary9d524f22016-03-29 09:03:52 -07002691
halcanary96fcdcc2015-08-27 07:41:13 -07002692 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002693 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002694 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002695 }
2696 LOOPER_END
2697}
2698
reedf70b5312016-03-04 16:36:20 -08002699void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2700 SkASSERT(key);
2701
2702 SkPaint paint;
2703 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2704 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002705 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002706 }
2707 LOOPER_END
2708}
2709
reed@android.com8a1c16f2008-12-17 15:59:43 +00002710//////////////////////////////////////////////////////////////////////////////
2711// These methods are NOT virtual, and therefore must call back into virtual
2712// methods, rather than actually drawing themselves.
2713//////////////////////////////////////////////////////////////////////////////
2714
reed374772b2016-10-05 17:33:02 -07002715void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002716 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002717 SkPaint paint;
2718
2719 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002720 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721 this->drawPaint(paint);
2722}
2723
2724void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002725 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002726 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2728}
2729
Mike Reed3661bc92017-02-22 13:21:42 -05002730void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002731 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002732 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002733
reed@android.com8a1c16f2008-12-17 15:59:43 +00002734 pts[0].set(x0, y0);
2735 pts[1].set(x1, y1);
2736 this->drawPoints(kLines_PointMode, 2, pts, paint);
2737}
2738
Mike Reed3661bc92017-02-22 13:21:42 -05002739void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002740 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741 if (radius < 0) {
2742 radius = 0;
2743 }
2744
2745 SkRect r;
2746 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002747 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748}
2749
2750void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2751 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002752 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002754 SkRRect rrect;
2755 rrect.setRectXY(r, rx, ry);
2756 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002757 } else {
2758 this->drawRect(r, paint);
2759 }
2760}
2761
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2763 SkScalar sweepAngle, bool useCenter,
2764 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002765 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002766 if (oval.isEmpty() || !sweepAngle) {
2767 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002768 }
bsalomon21af9ca2016-08-25 12:29:23 -07002769 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770}
2771
2772void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2773 const SkPath& path, SkScalar hOffset,
2774 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002775 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002777
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778 matrix.setTranslate(hOffset, vOffset);
2779 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2780}
2781
reed@android.comf76bacf2009-05-13 14:00:33 +00002782///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002783
2784/**
2785 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2786 * against the playback cost of recursing into the subpicture to get at its actual ops.
2787 *
2788 * For now we pick a conservatively small value, though measurement (and other heuristics like
2789 * the type of ops contained) may justify changing this value.
2790 */
2791#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002792
reedd5fa1a42014-08-09 11:08:05 -07002793void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002794 RETURN_ON_NULL(picture);
2795
reed1c2c4412015-04-30 13:09:24 -07002796 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002797 if (matrix && matrix->isIdentity()) {
2798 matrix = nullptr;
2799 }
2800 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2801 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2802 picture->playback(this);
2803 } else {
2804 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002805 }
2806}
robertphillips9b14f262014-06-04 05:40:44 -07002807
reedd5fa1a42014-08-09 11:08:05 -07002808void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2809 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002810 if (!paint || paint->canComputeFastBounds()) {
2811 SkRect bounds = picture->cullRect();
2812 if (paint) {
2813 paint->computeFastBounds(bounds, &bounds);
2814 }
2815 if (matrix) {
2816 matrix->mapRect(&bounds);
2817 }
2818 if (this->quickReject(bounds)) {
2819 return;
2820 }
2821 }
2822
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002823 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002824 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825}
2826
reed@android.com8a1c16f2008-12-17 15:59:43 +00002827///////////////////////////////////////////////////////////////////////////////
2828///////////////////////////////////////////////////////////////////////////////
2829
reed3aafe112016-08-18 12:45:34 -07002830SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002831 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002832
2833 SkASSERT(canvas);
2834
reed3aafe112016-08-18 12:45:34 -07002835 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002836 fDone = !fImpl->next();
2837}
2838
2839SkCanvas::LayerIter::~LayerIter() {
2840 fImpl->~SkDrawIter();
2841}
2842
2843void SkCanvas::LayerIter::next() {
2844 fDone = !fImpl->next();
2845}
2846
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002847SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002848 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849}
2850
2851const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002852 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002853}
2854
2855const SkPaint& SkCanvas::LayerIter::paint() const {
2856 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002857 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002858 paint = &fDefaultPaint;
2859 }
2860 return *paint;
2861}
2862
Mike Reeda1361362017-03-07 09:37:29 -05002863void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2864 return fImpl->fDevice->onAsRgnClip(rgn);
2865}
2866
reed@android.com8a1c16f2008-12-17 15:59:43 +00002867int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2868int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002869
2870///////////////////////////////////////////////////////////////////////////////
2871
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002872static bool supported_for_raster_canvas(const SkImageInfo& info) {
2873 switch (info.alphaType()) {
2874 case kPremul_SkAlphaType:
2875 case kOpaque_SkAlphaType:
2876 break;
2877 default:
2878 return false;
2879 }
2880
2881 switch (info.colorType()) {
2882 case kAlpha_8_SkColorType:
2883 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002884 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002885 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002886 break;
2887 default:
2888 return false;
2889 }
2890
2891 return true;
2892}
2893
Mike Reed5df49342016-11-12 08:06:55 -06002894std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
2895 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002896 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002897 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002898 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002899
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002900 SkBitmap bitmap;
2901 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002902 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002903 }
Mike Reed5df49342016-11-12 08:06:55 -06002904 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002905}
reedd5fa1a42014-08-09 11:08:05 -07002906
2907///////////////////////////////////////////////////////////////////////////////
2908
2909SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002910 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002911 : fCanvas(canvas)
2912 , fSaveCount(canvas->getSaveCount())
2913{
bsalomon49f085d2014-09-05 13:34:00 -07002914 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002915 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002916 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002917 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002918 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002919 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002920 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002921 canvas->save();
2922 }
mtklein6cfa73a2014-08-13 13:33:49 -07002923
bsalomon49f085d2014-09-05 13:34:00 -07002924 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002925 canvas->concat(*matrix);
2926 }
2927}
2928
2929SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2930 fCanvas->restoreToCount(fSaveCount);
2931}
reede8f30622016-03-23 18:59:25 -07002932
Florin Malitaee424ac2016-12-01 12:47:59 -05002933///////////////////////////////////////////////////////////////////////////////
2934
2935SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2936 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2937
Florin Malita439ace92016-12-02 12:05:41 -05002938SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2939 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2940
Florin Malitaee424ac2016-12-01 12:47:59 -05002941SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2942 (void)this->INHERITED::getSaveLayerStrategy(rec);
2943 return kNoLayer_SaveLayerStrategy;
2944}
2945
2946///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002947
reed73603f32016-09-20 08:42:38 -07002948static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2949static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2950static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2951static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2952static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2953static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002954
2955///////////////////////////////////////////////////////////////////////////////////////////////////
2956
2957SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2958 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002959 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002960 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2961 SkIPoint origin = dev->getOrigin();
2962 SkMatrix ctm = this->getTotalMatrix();
2963 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2964
2965 SkIRect clip = fMCRec->fRasterClip.getBounds();
2966 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002967 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002968 clip.setEmpty();
2969 }
2970
2971 fAllocator->updateHandle(handle, ctm, clip);
2972 return handle;
2973 }
2974 return nullptr;
2975}
2976
2977static bool install(SkBitmap* bm, const SkImageInfo& info,
2978 const SkRasterHandleAllocator::Rec& rec) {
2979 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
2980 rec.fReleaseProc, rec.fReleaseCtx);
2981}
2982
2983SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2984 SkBitmap* bm) {
2985 SkRasterHandleAllocator::Rec rec;
2986 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2987 return nullptr;
2988 }
2989 return rec.fHandle;
2990}
2991
2992std::unique_ptr<SkCanvas>
2993SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2994 const SkImageInfo& info, const Rec* rec) {
2995 if (!alloc || !supported_for_raster_canvas(info)) {
2996 return nullptr;
2997 }
2998
2999 SkBitmap bm;
3000 Handle hndl;
3001
3002 if (rec) {
3003 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3004 } else {
3005 hndl = alloc->allocBitmap(info, &bm);
3006 }
3007 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3008}