blob: 9f13a711c2508ca5a9e1c908dc28d7cd8a3f58cf [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Ben Wagner4bd3b092017-08-01 13:22:23 -040026#include "SkMSAN.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"
Mike Klein88d90712018-01-27 17:30:04 +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"
Brian Osman3b655982017-03-07 16:58:08 -050046#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070047
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050049#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050050#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051
reede3b38ce2016-01-08 09:18:44 -080052#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050053#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080054
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 {}
Hal Canaryb9642382017-06-27 09:58:56 -040093 void drawBitmap(const SkBitmap&, SkScalar x, SkScalar y, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -050094 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;
Florin Malita14a64302017-05-24 14:53:44 -0400529 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000530
531 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532};
533
reed@google.com129ec222012-05-15 13:24:09 +0000534bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700535 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000536 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700537 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000538
reeddbc3cef2015-04-29 12:18:57 -0700539 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
540 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000541
reed5c476fb2015-04-20 08:04:21 -0700542 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700543 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700544 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000545 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000546
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000547 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000548 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000549 return false;
550 }
551 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000552 if (!fFilter->filter(paint, drawType)) {
553 fDone = true;
554 return false;
555 }
halcanary96fcdcc2015-08-27 07:41:13 -0700556 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000557 // no looper means we only draw once
558 fDone = true;
559 }
560 }
561 fPaint = paint;
562
563 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000564 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000565 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000566 }
567
568 // call this after any possible paint modifiers
569 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700570 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000571 return false;
572 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000573 return true;
574}
575
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576////////// macros to place around the internal draw calls //////////////////
577
reed3aafe112016-08-18 12:45:34 -0700578#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
579 this->predrawNotify(); \
580 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
581 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800582 SkDrawIter iter(this);
583
584
reed@google.com8926b162012-03-23 15:36:36 +0000585#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000586 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700587 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000588 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000589 SkDrawIter iter(this);
590
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000591#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000592 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700593 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000594 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000596
reedc83a2972015-07-16 07:40:45 -0700597#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
598 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700599 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700600 while (looper.next(type)) { \
601 SkDrawIter iter(this);
602
reed@google.com4e2b3d32011-04-07 14:18:59 +0000603#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000604
605////////////////////////////////////////////////////////////////////////////
606
msarettfbfa2582016-08-12 08:29:08 -0700607static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
608 if (bounds.isEmpty()) {
609 return SkRect::MakeEmpty();
610 }
611
612 // Expand bounds out by 1 in case we are anti-aliasing. We store the
613 // bounds as floats to enable a faster quick reject implementation.
614 SkRect dst;
615 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
616 return dst;
617}
618
mtkleinfeaadee2015-04-08 11:25:48 -0700619void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
620 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700621 fMCRec->reset(bounds);
622
623 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500624 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400625 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700626 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700627 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700628}
629
reedd9544982014-09-09 18:46:22 -0700630SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800631 if (device && device->forceConservativeRasterClip()) {
632 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
633 }
reed42b73eb2015-11-20 13:42:42 -0800634
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000635 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800636 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700637 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638
639 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500640 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500641 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700642 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643
reeda499f902015-05-01 09:34:31 -0700644 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
645 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400646 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700647
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649
halcanary96fcdcc2015-08-27 07:41:13 -0700650 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000651
reedf92c8662014-08-18 08:02:43 -0700652 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700653 // The root device and the canvas should always have the same pixel geometry
654 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800655 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700656 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500657
Mike Reedc42a1cd2017-02-14 14:25:14 -0500658 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700659 }
msarettfbfa2582016-08-12 08:29:08 -0700660
reedf92c8662014-08-18 08:02:43 -0700661 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662}
663
reed@google.comcde92112011-07-06 20:00:52 +0000664SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000665 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700666 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000667{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000668 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000669
halcanary96fcdcc2015-08-27 07:41:13 -0700670 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000671}
672
reed96a857e2015-01-25 10:33:58 -0800673SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000674 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800675 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000676{
677 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700678
Mike Reed566e53c2017-03-10 10:49:45 -0500679 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700680 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700681}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000682
reed78e27682014-11-19 08:04:34 -0800683SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700684 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700685 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700686{
687 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700688
Mike Reed566e53c2017-03-10 10:49:45 -0500689 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
690 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700691}
692
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000693SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000694 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700695 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000696{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700698
reedd9544982014-09-09 18:46:22 -0700699 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000700}
701
robertphillipsfcf78292015-06-19 11:49:52 -0700702SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
703 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700704 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700705{
706 inc_canvas();
707
708 this->init(device, flags);
709}
710
reed4a8126e2014-09-22 07:29:03 -0700711SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700712 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700713 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700714{
715 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700716
Hal Canary704cd322016-11-07 14:13:52 -0500717 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
718 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700719}
reed29c857d2014-09-21 10:25:07 -0700720
Mike Reed356f7c22017-01-10 11:58:39 -0500721SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
722 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700723 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
724 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500725 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700726{
727 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700728
Mike Reed356f7c22017-01-10 11:58:39 -0500729 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500730 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000731}
732
Mike Reed356f7c22017-01-10 11:58:39 -0500733SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
734
Matt Sarett31f99ce2017-04-11 08:46:01 -0400735#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
736SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
737 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
738 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
739 , fAllocator(nullptr)
740{
741 inc_canvas();
742
743 SkBitmap tmp(bitmap);
744 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
745 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
746 this->init(device.get(), kDefault_InitFlags);
747}
748#endif
749
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750SkCanvas::~SkCanvas() {
751 // free up the contents of our deque
752 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000753
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754 this->internalRestore(); // restore the last, since we're going away
755
halcanary385fe4d2015-08-26 13:07:48 -0700756 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000757
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758 dec_canvas();
759}
760
fmalita53d9f1c2016-01-25 06:23:54 -0800761#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762SkDrawFilter* SkCanvas::getDrawFilter() const {
763 return fMCRec->fFilter;
764}
765
766SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700767 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
769 return filter;
770}
fmalita77650002016-01-21 18:47:11 -0800771#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000773SkMetaData& SkCanvas::getMetaData() {
774 // metadata users are rare, so we lazily allocate it. If that changes we
775 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700776 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000777 fMetaData = new SkMetaData;
778 }
779 return *fMetaData;
780}
781
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782///////////////////////////////////////////////////////////////////////////////
783
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000784void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700785 this->onFlush();
786}
787
788void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000789 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000790 if (device) {
791 device->flush();
792 }
793}
794
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000795SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000796 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000797 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
798}
799
senorblancoafc7cce2016-02-02 18:44:15 -0800800SkIRect SkCanvas::getTopLayerBounds() const {
801 SkBaseDevice* d = this->getTopDevice();
802 if (!d) {
803 return SkIRect::MakeEmpty();
804 }
805 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
806}
807
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000808SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000810 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000811 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400812 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813}
814
Florin Malita0ed3b642017-01-13 16:56:38 +0000815SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400816 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000817}
818
Mike Reed353196f2017-07-21 11:01:18 -0400819bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000820 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400821 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000822}
823
Mike Reed353196f2017-07-21 11:01:18 -0400824bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
825 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400826}
827
828bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
829 SkPixmap pm;
830 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
831}
832
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000833bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400834 SkPixmap pm;
835 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700836 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000837 }
838 return false;
839}
840
Matt Sarett03dd6d52017-01-23 12:15:09 -0500841bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000842 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000843 SkBaseDevice* device = this->getDevice();
844 if (!device) {
845 return false;
846 }
847
Matt Sarett03dd6d52017-01-23 12:15:09 -0500848 // This check gives us an early out and prevents generation ID churn on the surface.
849 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
850 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
851 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
852 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000853 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000854
Matt Sarett03dd6d52017-01-23 12:15:09 -0500855 // Tell our owning surface to bump its generation ID.
856 const bool completeOverwrite =
857 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700858 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700859
Matt Sarett03dd6d52017-01-23 12:15:09 -0500860 // This can still fail, most notably in the case of a invalid color type or alpha type
861 // conversion. We could pull those checks into this function and avoid the unnecessary
862 // generation ID bump. But then we would be performing those checks twice, since they
863 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400864 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000865}
reed@google.com51df9e32010-12-23 19:29:18 +0000866
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867//////////////////////////////////////////////////////////////////////////////
868
reed2ff1fce2014-12-11 07:07:37 -0800869void SkCanvas::checkForDeferredSave() {
870 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800871 this->doSave();
872 }
873}
874
reedf0090cb2014-11-26 08:55:51 -0800875int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800876#ifdef SK_DEBUG
877 int count = 0;
878 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
879 for (;;) {
880 const MCRec* rec = (const MCRec*)iter.next();
881 if (!rec) {
882 break;
883 }
884 count += 1 + rec->fDeferredSaveCount;
885 }
886 SkASSERT(count == fSaveCount);
887#endif
888 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800889}
890
891int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800892 fSaveCount += 1;
893 fMCRec->fDeferredSaveCount += 1;
894 return this->getSaveCount() - 1; // return our prev value
895}
896
897void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800898 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700899
900 SkASSERT(fMCRec->fDeferredSaveCount > 0);
901 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800902 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800903}
904
905void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800906 if (fMCRec->fDeferredSaveCount > 0) {
907 SkASSERT(fSaveCount > 1);
908 fSaveCount -= 1;
909 fMCRec->fDeferredSaveCount -= 1;
910 } else {
911 // check for underflow
912 if (fMCStack.count() > 1) {
913 this->willRestore();
914 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700915 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800916 this->internalRestore();
917 this->didRestore();
918 }
reedf0090cb2014-11-26 08:55:51 -0800919 }
920}
921
922void SkCanvas::restoreToCount(int count) {
923 // sanity check
924 if (count < 1) {
925 count = 1;
926 }
mtkleinf0f14112014-12-12 08:46:25 -0800927
reedf0090cb2014-11-26 08:55:51 -0800928 int n = this->getSaveCount() - count;
929 for (int i = 0; i < n; ++i) {
930 this->restore();
931 }
932}
933
reed2ff1fce2014-12-11 07:07:37 -0800934void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000935 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700936 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000937 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000938
Mike Reedc42a1cd2017-02-14 14:25:14 -0500939 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000940}
941
reed4960eee2015-12-18 07:09:18 -0800942bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800943 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944}
945
reed4960eee2015-12-18 07:09:18 -0800946bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700947 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500948 SkIRect clipBounds = this->getDeviceClipBounds();
949 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000950 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000951 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000952
reed96e657d2015-03-10 17:30:07 -0700953 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
954
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000955 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700956 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800957 if (bounds && !imageFilter->canComputeFastBounds()) {
958 bounds = nullptr;
959 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000960 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000961 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700962 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000963 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700964 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 r.roundOut(&ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966 } else { // no user bounds, so just use the clip
967 ir = clipBounds;
968 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800969
970 // early exit if the layer's bounds are clipped out
971 if (!ir.intersect(clipBounds)) {
972 if (BoundsAffectsClip(saveLayerFlags)) {
973 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
974 fMCRec->fRasterClip.setEmpty();
975 fDeviceClipBounds.setEmpty();
976 }
977 return false;
978 }
reed180aec42015-03-11 10:39:04 -0700979 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980
reed4960eee2015-12-18 07:09:18 -0800981 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700982 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700983 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700984 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000985 }
986
987 if (intersection) {
988 *intersection = ir;
989 }
990 return true;
991}
992
reed4960eee2015-12-18 07:09:18 -0800993
reed4960eee2015-12-18 07:09:18 -0800994int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
995 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000996}
997
reed70ee31b2015-12-10 13:44:45 -0800998int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800999 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1000}
1001
1002int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001003 SkTCopyOnFirstWrite<SaveLayerRec> rec(origRec);
reed4960eee2015-12-18 07:09:18 -08001004 if (gIgnoreSaveLayerBounds) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001005 rec.writable()->fBounds = nullptr;
reed4960eee2015-12-18 07:09:18 -08001006 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001007
1008 SaveLayerStrategy strategy = this->getSaveLayerStrategy(*rec);
reed4960eee2015-12-18 07:09:18 -08001009 fSaveCount += 1;
Florin Malita53f77bd2017-04-28 13:48:37 -04001010 this->internalSaveLayer(*rec, strategy);
reed4960eee2015-12-18 07:09:18 -08001011 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001012}
1013
reeda2217ef2016-07-20 06:04:34 -07001014void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001015 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001016 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001017 SkDraw draw;
1018 SkRasterClip rc;
1019 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1020 if (!dst->accessPixels(&draw.fDst)) {
1021 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001022 }
reeda2217ef2016-07-20 06:04:34 -07001023 draw.fMatrix = &SkMatrix::I();
1024 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001025
1026 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001027 if (filter) {
1028 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1029 }
reeda2217ef2016-07-20 06:04:34 -07001030
Mike Reedc42a1cd2017-02-14 14:25:14 -05001031 int x = src->getOrigin().x() - dstOrigin.x();
1032 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001033 auto special = src->snapSpecial();
1034 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001035 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -07001036 }
robertphillips7354a4b2015-12-16 05:08:27 -08001037}
reed70ee31b2015-12-10 13:44:45 -08001038
reed129ed1c2016-02-22 06:42:31 -08001039static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1040 const SkPaint* paint) {
1041 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1042 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001043 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001044 const bool hasImageFilter = paint && paint->getImageFilter();
1045
1046 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1047 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1048 // force to L32
1049 return SkImageInfo::MakeN32(w, h, alphaType);
1050 } else {
1051 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001052 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001053 }
1054}
1055
reed4960eee2015-12-18 07:09:18 -08001056void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1057 const SkRect* bounds = rec.fBounds;
1058 const SkPaint* paint = rec.fPaint;
1059 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1060
reed8c30a812016-04-20 16:36:51 -07001061 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001062 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001063 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001064 SkMatrix remainder;
1065 SkSize scale;
1066 /*
1067 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1068 * but they do handle scaling. To accommodate this, we do the following:
1069 *
1070 * 1. Stash off the current CTM
1071 * 2. Decompose the CTM into SCALE and REMAINDER
1072 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1073 * contains the REMAINDER
1074 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1075 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1076 * of the original imagefilter, and draw that (via drawSprite)
1077 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1078 *
1079 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1080 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1081 */
reed96a04f32016-04-25 09:25:15 -07001082 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001083 stashedMatrix.decomposeScale(&scale, &remainder))
1084 {
1085 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1086 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1087 SkPaint* p = lazyP.set(*paint);
1088 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1089 SkFilterQuality::kLow_SkFilterQuality,
1090 sk_ref_sp(imageFilter)));
1091 imageFilter = p->getImageFilter();
1092 paint = p;
1093 }
reed8c30a812016-04-20 16:36:51 -07001094
junov@chromium.orga907ac32012-02-24 21:54:07 +00001095 // do this before we create the layer. We don't call the public save() since
1096 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001097 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001098
junov@chromium.orga907ac32012-02-24 21:54:07 +00001099 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001100 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001101 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001102 }
1103
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001104 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1105 // the clipRectBounds() call above?
1106 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001107 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001108 }
1109
reed4960eee2015-12-18 07:09:18 -08001110 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001111 SkPixelGeometry geo = fProps.pixelGeometry();
1112 if (paint) {
reed76033be2015-03-14 10:54:31 -07001113 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001114 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001115 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001116 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001117 }
1118 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001119
robertphillips5139e502016-07-19 05:10:40 -07001120 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001121 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001122 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001123 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001124 }
reedb2db8982014-11-13 12:41:02 -08001125
robertphillips5139e502016-07-19 05:10:40 -07001126 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001127 paint);
1128
Hal Canary704cd322016-11-07 14:13:52 -05001129 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001130 {
reed70ee31b2015-12-10 13:44:45 -08001131 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001132 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001133 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001134 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001135 preserveLCDText,
1136 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001137 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1138 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001139 return;
reed61f501f2015-04-29 08:34:00 -07001140 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001141 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001142 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001143
Mike Reedb43a3e02017-02-11 10:18:58 -05001144 // only have a "next" if this new layer doesn't affect the clip (rare)
1145 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001146 fMCRec->fLayer = layer;
1147 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001148
Mike Reedc61abee2017-02-28 17:45:27 -05001149 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001150 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001151 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001152 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001153
Mike Reedc42a1cd2017-02-14 14:25:14 -05001154 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1155
1156 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1157 if (layer->fNext) {
1158 // need to punch a hole in the previous device, so we don't draw there, given that
1159 // the new top-layer will allow drawing to happen "below" it.
1160 SkRegion hole(ir);
1161 do {
1162 layer = layer->fNext;
1163 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1164 } while (layer->fNext);
1165 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001166}
1167
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001168int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001169 if (0xFF == alpha) {
1170 return this->saveLayer(bounds, nullptr);
1171 } else {
1172 SkPaint tmpPaint;
1173 tmpPaint.setAlpha(alpha);
1174 return this->saveLayer(bounds, &tmpPaint);
1175 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001176}
1177
reed@android.com8a1c16f2008-12-17 15:59:43 +00001178void SkCanvas::internalRestore() {
1179 SkASSERT(fMCStack.count() != 0);
1180
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001181 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182 DeviceCM* layer = fMCRec->fLayer; // may be null
1183 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001184 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001185
1186 // now do the normal restore()
1187 fMCRec->~MCRec(); // balanced in save()
1188 fMCStack.pop_back();
1189 fMCRec = (MCRec*)fMCStack.back();
1190
Mike Reedc42a1cd2017-02-14 14:25:14 -05001191 if (fMCRec) {
1192 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1193 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001194
reed@android.com8a1c16f2008-12-17 15:59:43 +00001195 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1196 since if we're being recorded, we don't want to record this (the
1197 recorder will have already recorded the restore).
1198 */
bsalomon49f085d2014-09-05 13:34:00 -07001199 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001200 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001201 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001202 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001203 layer->fPaint.get(),
1204 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001205 // restore what we smashed in internalSaveLayer
1206 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001207 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001208 delete layer;
reedb679ca82015-04-07 04:40:48 -07001209 } else {
1210 // we're at the root
reeda499f902015-05-01 09:34:31 -07001211 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001212 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001213 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001214 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001215 }
msarettfbfa2582016-08-12 08:29:08 -07001216
1217 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001218 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001219 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1220 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221}
1222
reede8f30622016-03-23 18:59:25 -07001223sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001224 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001225 props = &fProps;
1226 }
1227 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001228}
1229
reede8f30622016-03-23 18:59:25 -07001230sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001231 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001232 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001233}
1234
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001235SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001236 return this->onImageInfo();
1237}
1238
1239SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001240 SkBaseDevice* dev = this->getDevice();
1241 if (dev) {
1242 return dev->imageInfo();
1243 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001244 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001245 }
1246}
1247
brianosman898235c2016-04-06 07:38:23 -07001248bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001249 return this->onGetProps(props);
1250}
1251
1252bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001253 SkBaseDevice* dev = this->getDevice();
1254 if (dev) {
1255 if (props) {
1256 *props = fProps;
1257 }
1258 return true;
1259 } else {
1260 return false;
1261 }
1262}
1263
reed6ceeebd2016-03-09 14:26:26 -08001264bool SkCanvas::peekPixels(SkPixmap* pmap) {
1265 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001266}
1267
reed884e97c2015-05-26 11:31:54 -07001268bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001269 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001270 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001271}
1272
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001273void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001274 SkPixmap pmap;
1275 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001276 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001277 }
1278 if (info) {
1279 *info = pmap.info();
1280 }
1281 if (rowBytes) {
1282 *rowBytes = pmap.rowBytes();
1283 }
1284 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001285 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001286 }
reed884e97c2015-05-26 11:31:54 -07001287 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001288}
1289
reed884e97c2015-05-26 11:31:54 -07001290bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001291 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001292 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001293}
1294
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296
Florin Malita53f77bd2017-04-28 13:48:37 -04001297void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1298 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001300 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301 paint = &tmp;
1302 }
reed@google.com4b226022011-01-11 18:32:13 +00001303
reed@google.com8926b162012-03-23 15:36:36 +00001304 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001305
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001307 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001308 paint = &looper.paint();
1309 SkImageFilter* filter = paint->getImageFilter();
1310 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001311 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001312 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1313 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001314 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1315 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001316 }
reed@google.com76dd2772012-01-05 21:15:07 +00001317 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001318 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001319 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320 }
reeda2217ef2016-07-20 06:04:34 -07001321
reed@google.com4e2b3d32011-04-07 14:18:59 +00001322 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323}
1324
reed32704672015-12-16 08:27:10 -08001325/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001326
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001327void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001328 if (dx || dy) {
1329 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001330 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001331
reedfe69b502016-09-12 06:31:48 -07001332 // Translate shouldn't affect the is-scale-translateness of the matrix.
1333 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001334
Mike Reedc42a1cd2017-02-14 14:25:14 -05001335 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001336
reedfe69b502016-09-12 06:31:48 -07001337 this->didTranslate(dx,dy);
1338 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339}
1340
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001341void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001342 SkMatrix m;
1343 m.setScale(sx, sy);
1344 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001345}
1346
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001347void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001348 SkMatrix m;
1349 m.setRotate(degrees);
1350 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001351}
1352
bungeman7438bfc2016-07-12 15:01:19 -07001353void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1354 SkMatrix m;
1355 m.setRotate(degrees, px, py);
1356 this->concat(m);
1357}
1358
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001359void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001360 SkMatrix m;
1361 m.setSkew(sx, sy);
1362 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001363}
1364
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001365void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001366 if (matrix.isIdentity()) {
1367 return;
1368 }
1369
reed2ff1fce2014-12-11 07:07:37 -08001370 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001371 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001372 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001373
Mike Reed7627fa52017-02-08 10:07:53 -05001374 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001375
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001376 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001377}
1378
reed8c30a812016-04-20 16:36:51 -07001379void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001380 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001381 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001382
Mike Reedc42a1cd2017-02-14 14:25:14 -05001383 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001384}
1385
1386void SkCanvas::setMatrix(const SkMatrix& matrix) {
1387 this->checkForDeferredSave();
1388 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001389 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001390}
1391
reed@android.com8a1c16f2008-12-17 15:59:43 +00001392void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001393 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001394}
1395
1396//////////////////////////////////////////////////////////////////////////////
1397
Mike Reedc1f77742016-12-09 09:00:50 -05001398void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001399 if (!rect.isFinite()) {
1400 return;
1401 }
reed2ff1fce2014-12-11 07:07:37 -08001402 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001403 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1404 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001405}
1406
Mike Reedc1f77742016-12-09 09:00:50 -05001407void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001408 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001409
Mike Reed7627fa52017-02-08 10:07:53 -05001410 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001411
reedc64eff52015-11-21 12:39:45 -08001412 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001413 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1414 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001415 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416}
1417
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001418void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1419 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001420 if (fClipRestrictionRect.isEmpty()) {
1421 // we notify the device, but we *dont* resolve deferred saves (since we're just
1422 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001423 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001424 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001425 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001426 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001427 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001428 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001429 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1430 }
1431}
1432
Mike Reedc1f77742016-12-09 09:00:50 -05001433void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001434 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001435 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001436 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1438 } else {
1439 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001440 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001441}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001442
Mike Reedc1f77742016-12-09 09:00:50 -05001443void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001444 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001445
Brian Salomona3b45d42016-10-03 11:36:16 -04001446 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001447
Mike Reed7627fa52017-02-08 10:07:53 -05001448 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001449
Mike Reed20800c82017-11-15 16:09:04 -05001450 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1451 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001452 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001453}
1454
Mike Reedc1f77742016-12-09 09:00:50 -05001455void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001456 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001457 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001458
1459 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1460 SkRect r;
1461 if (path.isRect(&r)) {
1462 this->onClipRect(r, op, edgeStyle);
1463 return;
1464 }
1465 SkRRect rrect;
1466 if (path.isOval(&r)) {
1467 rrect.setOval(r);
1468 this->onClipRRect(rrect, op, edgeStyle);
1469 return;
1470 }
1471 if (path.isRRect(&rrect)) {
1472 this->onClipRRect(rrect, op, edgeStyle);
1473 return;
1474 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001475 }
robertphillips39f05382015-11-24 09:30:12 -08001476
1477 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001478}
1479
Mike Reedc1f77742016-12-09 09:00:50 -05001480void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001481 AutoValidateClip avc(this);
1482
Brian Salomona3b45d42016-10-03 11:36:16 -04001483 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001484
Mike Reed7627fa52017-02-08 10:07:53 -05001485 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486
Brian Salomona3b45d42016-10-03 11:36:16 -04001487 const SkPath* rasterClipPath = &path;
1488 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001489 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1490 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001491 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001492}
1493
Mike Reedc1f77742016-12-09 09:00:50 -05001494void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001495 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001496 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001497}
1498
Mike Reedc1f77742016-12-09 09:00:50 -05001499void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001500 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001501
reed@google.com5c3d1472011-02-22 19:12:23 +00001502 AutoValidateClip avc(this);
1503
Mike Reed20800c82017-11-15 16:09:04 -05001504 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001505 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001506}
1507
reed@google.com819c9212011-02-23 18:56:55 +00001508#ifdef SK_DEBUG
1509void SkCanvas::validateClip() const {
1510 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001511 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001512 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001513 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001514 return;
1515 }
reed@google.com819c9212011-02-23 18:56:55 +00001516}
1517#endif
1518
Mike Reeda1361362017-03-07 09:37:29 -05001519bool SkCanvas::androidFramework_isClipAA() const {
1520 bool containsAA = false;
1521
1522 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1523
1524 return containsAA;
1525}
1526
1527class RgnAccumulator {
1528 SkRegion* fRgn;
1529public:
1530 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1531 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1532 SkIPoint origin = device->getOrigin();
1533 if (origin.x() | origin.y()) {
1534 rgn->translate(origin.x(), origin.y());
1535 }
1536 fRgn->op(*rgn, SkRegion::kUnion_Op);
1537 }
1538};
1539
1540void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1541 RgnAccumulator accum(rgn);
1542 SkRegion tmp;
1543
1544 rgn->setEmpty();
1545 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001546}
1547
reed@google.com5c3d1472011-02-22 19:12:23 +00001548///////////////////////////////////////////////////////////////////////////////
1549
reed@google.com754de5f2014-02-24 19:38:20 +00001550bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001551 return fMCRec->fRasterClip.isEmpty();
1552
1553 // TODO: should we only use the conservative answer in a recording canvas?
1554#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001555 SkBaseDevice* dev = this->getTopDevice();
1556 // if no device we return true
1557 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001558#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001559}
1560
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001561bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001562 SkBaseDevice* dev = this->getTopDevice();
1563 // if no device we return false
1564 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001565}
1566
msarettfbfa2582016-08-12 08:29:08 -07001567static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1568#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1569 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1570 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1571 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1572 return 0xF != _mm_movemask_ps(mask);
1573#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1574 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1575 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1576 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1577 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1578#else
1579 SkRect devRectAsRect;
1580 SkRect devClipAsRect;
1581 devRect.store(&devRectAsRect.fLeft);
1582 devClip.store(&devClipAsRect.fLeft);
1583 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1584#endif
1585}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001586
msarettfbfa2582016-08-12 08:29:08 -07001587// It's important for this function to not be inlined. Otherwise the compiler will share code
1588// between the fast path and the slow path, resulting in two slow paths.
1589static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1590 const SkMatrix& matrix) {
1591 SkRect deviceRect;
1592 matrix.mapRect(&deviceRect, src);
1593 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1594}
1595
1596bool SkCanvas::quickReject(const SkRect& src) const {
1597#ifdef SK_DEBUG
1598 // Verify that fDeviceClipBounds are set properly.
1599 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001600 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001601 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001602 } else {
msarettfbfa2582016-08-12 08:29:08 -07001603 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001604 }
msarettfbfa2582016-08-12 08:29:08 -07001605
msarett9637ea92016-08-18 14:03:30 -07001606 // Verify that fIsScaleTranslate is set properly.
1607 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001608#endif
1609
msarett9637ea92016-08-18 14:03:30 -07001610 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001611 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1612 }
1613
1614 // We inline the implementation of mapScaleTranslate() for the fast path.
1615 float sx = fMCRec->fMatrix.getScaleX();
1616 float sy = fMCRec->fMatrix.getScaleY();
1617 float tx = fMCRec->fMatrix.getTranslateX();
1618 float ty = fMCRec->fMatrix.getTranslateY();
1619 Sk4f scale(sx, sy, sx, sy);
1620 Sk4f trans(tx, ty, tx, ty);
1621
1622 // Apply matrix.
1623 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1624
1625 // Make sure left < right, top < bottom.
1626 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1627 Sk4f min = Sk4f::Min(ltrb, rblt);
1628 Sk4f max = Sk4f::Max(ltrb, rblt);
1629 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1630 // ARM this sequence generates the fastest (a single instruction).
1631 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1632
1633 // Check if the device rect is NaN or outside the clip.
1634 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001635}
1636
reed@google.com3b3e8952012-08-16 20:53:31 +00001637bool SkCanvas::quickReject(const SkPath& path) const {
1638 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001639}
1640
Mike Klein83c8dd92017-11-28 17:08:45 -05001641SkRect SkCanvas::getLocalClipBounds() const {
1642 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001643 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001644 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001645 }
1646
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001647 SkMatrix inverse;
1648 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001649 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001650 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001651 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652
Mike Reed42e8c532017-01-23 14:09:13 -05001653 SkRect bounds;
1654 SkRect r;
1655 // adjust it outwards in case we are antialiasing
1656 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001657
Mike Reed42e8c532017-01-23 14:09:13 -05001658 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1659 ibounds.fRight + inset, ibounds.fBottom + inset);
1660 inverse.mapRect(&bounds, r);
1661 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662}
1663
Mike Klein83c8dd92017-11-28 17:08:45 -05001664SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001665 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001666}
1667
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001669 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001670}
1671
Brian Osman11052242016-10-27 14:47:55 -04001672GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001673 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001674 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001675}
1676
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001677GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001678 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001679 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001680}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001681
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001682void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1683 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001684 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001685 if (outer.isEmpty()) {
1686 return;
1687 }
1688 if (inner.isEmpty()) {
1689 this->drawRRect(outer, paint);
1690 return;
1691 }
1692
1693 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001694 // be able to return ...
1695 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001696 //
1697 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001698 if (!outer.getBounds().contains(inner.getBounds())) {
1699 return;
1700 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001701
1702 this->onDrawDRRect(outer, inner, paint);
1703}
1704
reed41af9662015-01-05 07:49:08 -08001705void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001706 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001707 this->onDrawPaint(paint);
1708}
1709
1710void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001711 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001712 // To avoid redundant logic in our culling code and various backends, we always sort rects
1713 // before passing them along.
1714 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001715}
1716
msarettdca352e2016-08-26 06:37:45 -07001717void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001718 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001719 if (region.isEmpty()) {
1720 return;
1721 }
1722
1723 if (region.isRect()) {
1724 return this->drawIRect(region.getBounds(), paint);
1725 }
1726
1727 this->onDrawRegion(region, paint);
1728}
1729
reed41af9662015-01-05 07:49:08 -08001730void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001731 TRACE_EVENT0("skia", TRACE_FUNC);
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) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001738 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001739 this->onDrawRRect(rrect, paint);
1740}
1741
1742void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001743 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001744 this->onDrawPoints(mode, count, pts, paint);
1745}
1746
Mike Reede88a1cb2017-03-17 09:50:46 -04001747void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1748 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001749 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001750 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001751 this->onDrawVerticesObject(vertices.get(), mode, paint);
1752}
1753
1754void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001755 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001756 RETURN_ON_NULL(vertices);
1757 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001758}
1759
1760void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001761 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001762 this->onDrawPath(path, paint);
1763}
1764
reeda85d4d02015-05-06 12:56:48 -07001765void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001766 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001767 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001768 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001769}
1770
Mike Reedc4e31092018-01-30 11:15:27 -05001771// Returns true if the rect can be "filled" : non-empty and finite
1772static bool fillable(const SkRect& r) {
1773 SkScalar w = r.width();
1774 SkScalar h = r.height();
1775 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1776}
1777
reede47829b2015-08-06 10:02:53 -07001778void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1779 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001780 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001781 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001782 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001783 return;
1784 }
1785 this->onDrawImageRect(image, &src, dst, paint, constraint);
1786}
reed41af9662015-01-05 07:49:08 -08001787
reed84984ef2015-07-17 07:09:43 -07001788void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1789 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001790 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001791 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001792}
1793
reede47829b2015-08-06 10:02:53 -07001794void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1795 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001796 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001797 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1798 constraint);
1799}
reede47829b2015-08-06 10:02:53 -07001800
reed4c21dc52015-06-25 12:32:03 -07001801void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1802 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001803 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001804 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001805 if (dst.isEmpty()) {
1806 return;
1807 }
msarett552bca92016-08-03 06:53:26 -07001808 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1809 this->onDrawImageNine(image, center, dst, paint);
1810 } else {
reede47829b2015-08-06 10:02:53 -07001811 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001812 }
reed4c21dc52015-06-25 12:32:03 -07001813}
1814
msarett16882062016-08-16 09:31:08 -07001815void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1816 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001817 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001818 RETURN_ON_NULL(image);
1819 if (dst.isEmpty()) {
1820 return;
1821 }
msarett71df2d72016-09-30 12:41:42 -07001822
1823 SkIRect bounds;
1824 Lattice latticePlusBounds = lattice;
1825 if (!latticePlusBounds.fBounds) {
1826 bounds = SkIRect::MakeWH(image->width(), image->height());
1827 latticePlusBounds.fBounds = &bounds;
1828 }
1829
1830 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1831 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001832 } else {
1833 this->drawImageRect(image, dst, paint);
1834 }
1835}
1836
reed41af9662015-01-05 07:49:08 -08001837void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001838 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001839 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001840 return;
1841 }
reed41af9662015-01-05 07:49:08 -08001842 this->onDrawBitmap(bitmap, dx, dy, paint);
1843}
1844
reede47829b2015-08-06 10:02:53 -07001845void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001846 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001847 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001848 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001849 return;
1850 }
reede47829b2015-08-06 10:02:53 -07001851 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001852}
1853
reed84984ef2015-07-17 07:09:43 -07001854void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1855 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001856 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001857}
1858
reede47829b2015-08-06 10:02:53 -07001859void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1860 SrcRectConstraint constraint) {
1861 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1862 constraint);
1863}
reede47829b2015-08-06 10:02:53 -07001864
reed41af9662015-01-05 07:49:08 -08001865void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1866 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001867 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001868 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001869 return;
1870 }
msarett552bca92016-08-03 06:53:26 -07001871 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1872 this->onDrawBitmapNine(bitmap, center, dst, paint);
1873 } else {
reeda5517e22015-07-14 10:54:12 -07001874 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001875 }
reed41af9662015-01-05 07:49:08 -08001876}
1877
msarettc573a402016-08-02 08:05:56 -07001878void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1879 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001880 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001881 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001882 return;
1883 }
msarett71df2d72016-09-30 12:41:42 -07001884
1885 SkIRect bounds;
1886 Lattice latticePlusBounds = lattice;
1887 if (!latticePlusBounds.fBounds) {
1888 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1889 latticePlusBounds.fBounds = &bounds;
1890 }
1891
1892 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1893 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001894 } else {
msarett16882062016-08-16 09:31:08 -07001895 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001896 }
msarettc573a402016-08-02 08:05:56 -07001897}
1898
reed71c3c762015-06-24 10:29:17 -07001899void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001900 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001901 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001902 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001903 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001904 if (count <= 0) {
1905 return;
1906 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001907 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001908 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001909 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001910}
1911
reedf70b5312016-03-04 16:36:20 -08001912void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001913 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001914 if (key) {
1915 this->onDrawAnnotation(rect, key, value);
1916 }
1917}
1918
reede47829b2015-08-06 10:02:53 -07001919void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1920 const SkPaint* paint, SrcRectConstraint constraint) {
1921 if (src) {
1922 this->drawImageRect(image, *src, dst, paint, constraint);
1923 } else {
1924 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1925 dst, paint, constraint);
1926 }
1927}
1928void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1929 const SkPaint* paint, SrcRectConstraint constraint) {
1930 if (src) {
1931 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1932 } else {
1933 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1934 dst, paint, constraint);
1935 }
1936}
1937
Mike Reed4204da22017-05-17 08:53:36 -04001938void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001939 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001940 this->onDrawShadowRec(path, rec);
1941}
1942
1943void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1944 SkPaint paint;
1945 const SkRect& pathBounds = path.getBounds();
1946
1947 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1948 while (iter.next()) {
1949 iter.fDevice->drawShadow(path, rec);
1950 }
1951 LOOPER_END
1952}
1953
reed@android.com8a1c16f2008-12-17 15:59:43 +00001954//////////////////////////////////////////////////////////////////////////////
1955// These are the virtual drawing methods
1956//////////////////////////////////////////////////////////////////////////////
1957
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001958void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001959 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001960 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1961 }
1962}
1963
reed41af9662015-01-05 07:49:08 -08001964void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001965 this->internalDrawPaint(paint);
1966}
1967
1968void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001969 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001970
1971 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001972 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001973 }
1974
reed@google.com4e2b3d32011-04-07 14:18:59 +00001975 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001976}
1977
reed41af9662015-01-05 07:49:08 -08001978void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1979 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001980 if ((long)count <= 0) {
1981 return;
1982 }
1983
Mike Reed822128b2017-02-28 16:41:03 -05001984 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001985 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001986 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001987 // special-case 2 points (common for drawing a single line)
1988 if (2 == count) {
1989 r.set(pts[0], pts[1]);
1990 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001991 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001992 }
Mike Reed822128b2017-02-28 16:41:03 -05001993 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001994 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1995 return;
1996 }
1997 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001998 }
reed@google.coma584aed2012-05-16 14:06:02 +00001999
halcanary96fcdcc2015-08-27 07:41:13 -07002000 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002001
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002002 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002003
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002005 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002006 }
reed@google.com4b226022011-01-11 18:32:13 +00002007
reed@google.com4e2b3d32011-04-07 14:18:59 +00002008 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002009}
2010
reed4a167172016-08-18 17:15:25 -07002011static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2012 return ((intptr_t)paint.getImageFilter() |
2013#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2014 (intptr_t)canvas->getDrawFilter() |
2015#endif
2016 (intptr_t)paint.getLooper() ) != 0;
2017}
2018
reed41af9662015-01-05 07:49:08 -08002019void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002020 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002021 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002022 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002023 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002024 return;
2025 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002026 }
reed@google.com4b226022011-01-11 18:32:13 +00002027
reed4a167172016-08-18 17:15:25 -07002028 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002029 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002030
reed4a167172016-08-18 17:15:25 -07002031 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002032 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002033 }
2034
2035 LOOPER_END
2036 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002037 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002038 SkDrawIter iter(this);
2039 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002040 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002041 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002042 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002043}
2044
msarett44df6512016-08-25 13:54:30 -07002045void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002046 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002047 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002048 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002049 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2050 return;
2051 }
msarett44df6512016-08-25 13:54:30 -07002052 }
2053
Mike Reed822128b2017-02-28 16:41:03 -05002054 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002055
2056 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002057 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002058 }
2059
2060 LOOPER_END
2061}
2062
reed41af9662015-01-05 07:49:08 -08002063void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002064 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002065 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002066 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002067 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002068 return;
2069 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002070 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002071
Mike Reed822128b2017-02-28 16:41:03 -05002072 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002073
2074 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002075 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002076 }
2077
2078 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002079}
2080
bsalomonac3aa242016-08-19 11:25:19 -07002081void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2082 SkScalar sweepAngle, bool useCenter,
2083 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002084 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002085 if (paint.canComputeFastBounds()) {
2086 SkRect storage;
2087 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002088 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002089 return;
2090 }
bsalomonac3aa242016-08-19 11:25:19 -07002091 }
2092
Mike Reed822128b2017-02-28 16:41:03 -05002093 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002094
2095 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002096 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002097 }
2098
2099 LOOPER_END
2100}
2101
reed41af9662015-01-05 07:49:08 -08002102void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002103 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002104 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002105 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2106 return;
2107 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002108 }
2109
2110 if (rrect.isRect()) {
2111 // call the non-virtual version
2112 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002113 return;
2114 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002115 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002116 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2117 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002118 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002119
Mike Reed822128b2017-02-28 16:41:03 -05002120 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002121
2122 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002123 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002124 }
2125
2126 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002127}
2128
Mike Reed822128b2017-02-28 16:41:03 -05002129void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002130 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002131 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002132 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2133 return;
2134 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002135 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002136
Mike Reed822128b2017-02-28 16:41:03 -05002137 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002138
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002139 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002140 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002141 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002142
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002143 LOOPER_END
2144}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002145
reed41af9662015-01-05 07:49:08 -08002146void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002147 if (!path.isFinite()) {
2148 return;
2149 }
2150
Mike Reed822128b2017-02-28 16:41:03 -05002151 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002152 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002153 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002154 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2155 return;
2156 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002157 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002158
Mike Reed822128b2017-02-28 16:41:03 -05002159 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002160 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002161 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002162 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002163 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002164 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002165
Mike Reed822128b2017-02-28 16:41:03 -05002166 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002167
2168 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002169 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002170 }
2171
reed@google.com4e2b3d32011-04-07 14:18:59 +00002172 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002173}
2174
reed262a71b2015-12-05 13:07:27 -08002175bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002176 if (!paint.getImageFilter()) {
2177 return false;
2178 }
2179
2180 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002181 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002182 return false;
2183 }
2184
2185 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2186 // Once we can filter and the filter will return a result larger than itself, we should be
2187 // able to remove this constraint.
2188 // skbug.com/4526
2189 //
2190 SkPoint pt;
2191 ctm.mapXY(x, y, &pt);
2192 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2193 return ir.contains(fMCRec->fRasterClip.getBounds());
2194}
2195
reeda85d4d02015-05-06 12:56:48 -07002196void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07002197 SkRect bounds = SkRect::MakeXYWH(x, y,
2198 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002199 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002200 SkRect tmp = bounds;
2201 if (paint) {
2202 paint->computeFastBounds(tmp, &tmp);
2203 }
2204 if (this->quickReject(tmp)) {
2205 return;
2206 }
reeda85d4d02015-05-06 12:56:48 -07002207 }
halcanary9d524f22016-03-29 09:03:52 -07002208
reeda85d4d02015-05-06 12:56:48 -07002209 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002210 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002211 paint = lazy.init();
2212 }
reed262a71b2015-12-05 13:07:27 -08002213
reeda2217ef2016-07-20 06:04:34 -07002214 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002215 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2216 *paint);
2217 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002218 special = this->getDevice()->makeSpecial(image);
2219 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002220 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002221 }
2222 }
2223
reed262a71b2015-12-05 13:07:27 -08002224 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2225
reeda85d4d02015-05-06 12:56:48 -07002226 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002227 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002228 if (special) {
2229 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002230 iter.fDevice->ctm().mapXY(x, y, &pt);
2231 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002232 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002233 SkScalarRoundToInt(pt.fY), pnt,
2234 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002235 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002236 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002237 }
reeda85d4d02015-05-06 12:56:48 -07002238 }
halcanary9d524f22016-03-29 09:03:52 -07002239
reeda85d4d02015-05-06 12:56:48 -07002240 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002241}
2242
reed41af9662015-01-05 07:49:08 -08002243void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002244 const SkPaint* paint, SrcRectConstraint constraint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002245 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002246 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002247 if (paint) {
2248 paint->computeFastBounds(dst, &storage);
2249 }
2250 if (this->quickReject(storage)) {
2251 return;
2252 }
reeda85d4d02015-05-06 12:56:48 -07002253 }
2254 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002255 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002256 paint = lazy.init();
2257 }
halcanary9d524f22016-03-29 09:03:52 -07002258
senorblancoc41e7e12015-12-07 12:51:30 -08002259 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002260 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002261
reeda85d4d02015-05-06 12:56:48 -07002262 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002263 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002264 }
halcanary9d524f22016-03-29 09:03:52 -07002265
reeda85d4d02015-05-06 12:56:48 -07002266 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002267}
2268
reed41af9662015-01-05 07:49:08 -08002269void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002270 SkDEBUGCODE(bitmap.validate();)
2271
reed33366972015-10-08 09:22:02 -07002272 if (bitmap.drawsNothing()) {
2273 return;
2274 }
2275
2276 SkLazyPaint lazy;
2277 if (nullptr == paint) {
2278 paint = lazy.init();
2279 }
2280
Mike Reed822128b2017-02-28 16:41:03 -05002281 SkRect bounds;
2282 bitmap.getBounds(&bounds);
2283 bounds.offset(x, y);
2284 bool canFastBounds = paint->canComputeFastBounds();
2285 if (canFastBounds) {
2286 SkRect storage;
2287 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002288 return;
2289 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290 }
reed@google.com4b226022011-01-11 18:32:13 +00002291
reeda2217ef2016-07-20 06:04:34 -07002292 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002293 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2294 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002295 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002296 special = this->getDevice()->makeSpecial(bitmap);
2297 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002298 drawAsSprite = false;
2299 }
2300 }
2301
Mike Reed822128b2017-02-28 16:41:03 -05002302 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002303
2304 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002305 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002306 if (special) {
reed262a71b2015-12-05 13:07:27 -08002307 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002308 iter.fDevice->ctm().mapXY(x, y, &pt);
2309 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002310 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002311 SkScalarRoundToInt(pt.fY), pnt,
2312 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002313 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002314 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002315 }
reed33366972015-10-08 09:22:02 -07002316 }
msarettfbfa2582016-08-12 08:29:08 -07002317
reed33366972015-10-08 09:22:02 -07002318 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002319}
2320
reed@google.com9987ec32011-09-07 11:57:52 +00002321// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002322void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002323 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002324 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002325 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002326 return;
2327 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002328
halcanary96fcdcc2015-08-27 07:41:13 -07002329 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002330 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002331 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2332 return;
2333 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002334 }
reed@google.com3d608122011-11-21 15:16:16 +00002335
reed@google.com33535f32012-09-25 15:37:50 +00002336 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002337 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002338 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002339 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002340
senorblancoc41e7e12015-12-07 12:51:30 -08002341 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002342 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002343
reed@google.com33535f32012-09-25 15:37:50 +00002344 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002345 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002346 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002347
reed@google.com33535f32012-09-25 15:37:50 +00002348 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002349}
2350
reed41af9662015-01-05 07:49:08 -08002351void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002352 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002353 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002354 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002355}
2356
reed4c21dc52015-06-25 12:32:03 -07002357void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2358 const SkPaint* paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002359 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002360 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002361 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2362 return;
2363 }
reed@google.com3d608122011-11-21 15:16:16 +00002364 }
halcanary9d524f22016-03-29 09:03:52 -07002365
reed4c21dc52015-06-25 12:32:03 -07002366 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002367 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002368 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002369 }
halcanary9d524f22016-03-29 09:03:52 -07002370
senorblancoc41e7e12015-12-07 12:51:30 -08002371 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002372
reed4c21dc52015-06-25 12:32:03 -07002373 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002374 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002375 }
halcanary9d524f22016-03-29 09:03:52 -07002376
reed4c21dc52015-06-25 12:32:03 -07002377 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002378}
2379
reed41af9662015-01-05 07:49:08 -08002380void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2381 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002382 SkDEBUGCODE(bitmap.validate();)
2383
halcanary96fcdcc2015-08-27 07:41:13 -07002384 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002385 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002386 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2387 return;
2388 }
reed4c21dc52015-06-25 12:32:03 -07002389 }
halcanary9d524f22016-03-29 09:03:52 -07002390
reed4c21dc52015-06-25 12:32:03 -07002391 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002392 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002393 paint = lazy.init();
2394 }
halcanary9d524f22016-03-29 09:03:52 -07002395
senorblancoc41e7e12015-12-07 12:51:30 -08002396 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002397
reed4c21dc52015-06-25 12:32:03 -07002398 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002399 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002400 }
halcanary9d524f22016-03-29 09:03:52 -07002401
reed4c21dc52015-06-25 12:32:03 -07002402 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002403}
2404
msarett16882062016-08-16 09:31:08 -07002405void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2406 const SkPaint* paint) {
2407 if (nullptr == paint || paint->canComputeFastBounds()) {
2408 SkRect storage;
2409 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2410 return;
2411 }
2412 }
2413
2414 SkLazyPaint lazy;
2415 if (nullptr == paint) {
2416 paint = lazy.init();
2417 }
2418
2419 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2420
2421 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002422 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002423 }
2424
2425 LOOPER_END
2426}
2427
2428void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2429 const SkRect& dst, const SkPaint* paint) {
2430 if (nullptr == paint || paint->canComputeFastBounds()) {
2431 SkRect storage;
2432 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2433 return;
2434 }
2435 }
2436
2437 SkLazyPaint lazy;
2438 if (nullptr == paint) {
2439 paint = lazy.init();
2440 }
2441
2442 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2443
2444 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002445 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002446 }
2447
2448 LOOPER_END
2449}
2450
reed@google.comf67e4cf2011-03-15 20:56:58 +00002451class SkDeviceFilteredPaint {
2452public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002453 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002454 uint32_t filteredFlags = device->filterTextFlags(paint);
2455 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002456 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002457 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002458 fPaint = newPaint;
2459 } else {
2460 fPaint = &paint;
2461 }
2462 }
2463
reed@google.comf67e4cf2011-03-15 20:56:58 +00002464 const SkPaint& paint() const { return *fPaint; }
2465
2466private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002467 const SkPaint* fPaint;
2468 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002469};
2470
reed@google.come0d9ce82014-04-23 04:00:17 +00002471void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2472 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002473 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474
2475 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002476 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002477 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478 }
2479
reed@google.com4e2b3d32011-04-07 14:18:59 +00002480 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481}
2482
reed@google.come0d9ce82014-04-23 04:00:17 +00002483void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2484 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002485 SkPoint textOffset = SkPoint::Make(0, 0);
2486
halcanary96fcdcc2015-08-27 07:41:13 -07002487 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002488
reed@android.com8a1c16f2008-12-17 15:59:43 +00002489 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002490 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002491 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002492 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002493 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002494
reed@google.com4e2b3d32011-04-07 14:18:59 +00002495 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496}
2497
reed@google.come0d9ce82014-04-23 04:00:17 +00002498void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2499 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002500
2501 SkPoint textOffset = SkPoint::Make(0, constY);
2502
halcanary96fcdcc2015-08-27 07:41:13 -07002503 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002504
reed@android.com8a1c16f2008-12-17 15:59:43 +00002505 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002506 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002507 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002508 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002509 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002510
reed@google.com4e2b3d32011-04-07 14:18:59 +00002511 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002512}
2513
reed@google.come0d9ce82014-04-23 04:00:17 +00002514void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2515 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002516 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002517
reed@android.com8a1c16f2008-12-17 15:59:43 +00002518 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002519 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002520 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002521 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002522
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002523 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002524}
2525
reed45561a02016-07-07 12:47:17 -07002526void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2527 const SkRect* cullRect, const SkPaint& paint) {
2528 if (cullRect && this->quickReject(*cullRect)) {
2529 return;
2530 }
2531
2532 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2533
2534 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002535 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002536 }
2537
2538 LOOPER_END
2539}
2540
fmalita00d5c2c2014-08-21 08:53:26 -07002541void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2542 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002543
fmalita85d5eb92015-03-04 11:20:12 -08002544 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002545 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002546 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002547 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002548 SkRect tmp;
2549 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2550 return;
2551 }
2552 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002553 }
2554
fmalita024f9962015-03-03 19:08:17 -08002555 // We cannot filter in the looper as we normally do, because the paint is
2556 // incomplete at this point (text-related attributes are embedded within blob run paints).
2557 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002558 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002559
fmalita85d5eb92015-03-04 11:20:12 -08002560 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002561
fmalitaaa1b9122014-08-28 14:32:24 -07002562 while (iter.next()) {
2563 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002564 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002565 }
2566
fmalitaaa1b9122014-08-28 14:32:24 -07002567 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002568
2569 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002570}
2571
Cary Clark2a475ea2017-04-28 15:35:12 -04002572void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2573 this->drawText(string.c_str(), string.size(), x, y, paint);
2574}
2575
reed@google.come0d9ce82014-04-23 04:00:17 +00002576// These will become non-virtual, so they always call the (virtual) onDraw... method
2577void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2578 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002579 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002580 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002581 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002582 this->onDrawText(text, byteLength, x, y, paint);
2583 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002584}
2585void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2586 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002587 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002588 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002589 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002590 this->onDrawPosText(text, byteLength, pos, paint);
2591 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002592}
2593void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2594 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002595 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002596 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002597 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002598 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2599 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002600}
2601void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2602 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002603 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002604 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002605 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002606 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2607 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002608}
reed45561a02016-07-07 12:47:17 -07002609void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2610 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002611 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002612 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002613 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002614 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2615 }
2616}
fmalita00d5c2c2014-08-21 08:53:26 -07002617void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2618 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002619 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002620 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002621 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002622 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002623}
reed@google.come0d9ce82014-04-23 04:00:17 +00002624
Mike Reede88a1cb2017-03-17 09:50:46 -04002625void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2626 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002627 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2628
2629 while (iter.next()) {
2630 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002631 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002632 }
2633
2634 LOOPER_END
2635}
2636
dandovb3c9d1c2014-08-12 08:34:29 -07002637void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002638 const SkPoint texCoords[4], SkBlendMode bmode,
2639 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002640 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002641 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002642 return;
2643 }
mtklein6cfa73a2014-08-13 13:33:49 -07002644
Mike Reedfaba3712016-11-03 14:45:31 -04002645 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002646}
2647
2648void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002649 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002650 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002651 // Since a patch is always within the convex hull of the control points, we discard it when its
2652 // bounding rectangle is completely outside the current clip.
2653 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002654 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002655 if (this->quickReject(bounds)) {
2656 return;
2657 }
mtklein6cfa73a2014-08-13 13:33:49 -07002658
Mike Reed435071e2017-05-23 11:22:56 -04002659 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2660
halcanary96fcdcc2015-08-27 07:41:13 -07002661 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002662
dandovecfff212014-08-04 10:02:00 -07002663 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002664 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002665 }
mtklein6cfa73a2014-08-13 13:33:49 -07002666
dandovecfff212014-08-04 10:02:00 -07002667 LOOPER_END
2668}
2669
reeda8db7282015-07-07 10:22:31 -07002670void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002671#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002672 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002673#endif
reede3b38ce2016-01-08 09:18:44 -08002674 RETURN_ON_NULL(dr);
2675 if (x || y) {
2676 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2677 this->onDrawDrawable(dr, &matrix);
2678 } else {
2679 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002680 }
2681}
2682
reeda8db7282015-07-07 10:22:31 -07002683void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002684#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002685 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002686#endif
reede3b38ce2016-01-08 09:18:44 -08002687 RETURN_ON_NULL(dr);
2688 if (matrix && matrix->isIdentity()) {
2689 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002690 }
reede3b38ce2016-01-08 09:18:44 -08002691 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002692}
2693
2694void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002695 // drawable bounds are no longer reliable (e.g. android displaylist)
2696 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002697 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002698}
2699
reed71c3c762015-06-24 10:29:17 -07002700void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002701 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002702 const SkRect* cull, const SkPaint* paint) {
2703 if (cull && this->quickReject(*cull)) {
2704 return;
2705 }
2706
2707 SkPaint pnt;
2708 if (paint) {
2709 pnt = *paint;
2710 }
halcanary9d524f22016-03-29 09:03:52 -07002711
halcanary96fcdcc2015-08-27 07:41:13 -07002712 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002713 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002714 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002715 }
2716 LOOPER_END
2717}
2718
reedf70b5312016-03-04 16:36:20 -08002719void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2720 SkASSERT(key);
2721
2722 SkPaint paint;
2723 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2724 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002725 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002726 }
2727 LOOPER_END
2728}
2729
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730//////////////////////////////////////////////////////////////////////////////
2731// These methods are NOT virtual, and therefore must call back into virtual
2732// methods, rather than actually drawing themselves.
2733//////////////////////////////////////////////////////////////////////////////
2734
reed374772b2016-10-05 17:33:02 -07002735void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002736 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002737 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002738 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002739 this->drawPaint(paint);
2740}
2741
2742void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002743 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002744 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2745}
2746
Mike Reed3661bc92017-02-22 13:21:42 -05002747void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002749 pts[0].set(x0, y0);
2750 pts[1].set(x1, y1);
2751 this->drawPoints(kLines_PointMode, 2, pts, paint);
2752}
2753
Mike Reed3661bc92017-02-22 13:21:42 -05002754void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002755 if (radius < 0) {
2756 radius = 0;
2757 }
2758
2759 SkRect r;
2760 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002761 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762}
2763
2764void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2765 const SkPaint& paint) {
2766 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002767 SkRRect rrect;
2768 rrect.setRectXY(r, rx, ry);
2769 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 } else {
2771 this->drawRect(r, paint);
2772 }
2773}
2774
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2776 SkScalar sweepAngle, bool useCenter,
2777 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002778 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002779 if (oval.isEmpty() || !sweepAngle) {
2780 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 }
bsalomon21af9ca2016-08-25 12:29:23 -07002782 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783}
2784
2785void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2786 const SkPath& path, SkScalar hOffset,
2787 SkScalar vOffset, const SkPaint& paint) {
2788 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002789
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790 matrix.setTranslate(hOffset, vOffset);
2791 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2792}
2793
reed@android.comf76bacf2009-05-13 14:00:33 +00002794///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002795
Mike Klein88d90712018-01-27 17:30:04 +00002796/**
2797 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2798 * against the playback cost of recursing into the subpicture to get at its actual ops.
2799 *
2800 * For now we pick a conservatively small value, though measurement (and other heuristics like
2801 * the type of ops contained) may justify changing this value.
2802 */
2803#define kMaxPictureOpsToUnrollInsteadOfRef 1
2804
reedd5fa1a42014-08-09 11:08:05 -07002805void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002806 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002807 RETURN_ON_NULL(picture);
2808
reede3b38ce2016-01-08 09:18:44 -08002809 if (matrix && matrix->isIdentity()) {
2810 matrix = nullptr;
2811 }
Mike Klein88d90712018-01-27 17:30:04 +00002812 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2813 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2814 picture->playback(this);
2815 } else {
2816 this->onDrawPicture(picture, matrix, paint);
2817 }
reedd5fa1a42014-08-09 11:08:05 -07002818}
robertphillips9b14f262014-06-04 05:40:44 -07002819
reedd5fa1a42014-08-09 11:08:05 -07002820void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2821 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002822 if (!paint || paint->canComputeFastBounds()) {
2823 SkRect bounds = picture->cullRect();
2824 if (paint) {
2825 paint->computeFastBounds(bounds, &bounds);
2826 }
2827 if (matrix) {
2828 matrix->mapRect(&bounds);
2829 }
2830 if (this->quickReject(bounds)) {
2831 return;
2832 }
2833 }
2834
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002835 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002836 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837}
2838
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839///////////////////////////////////////////////////////////////////////////////
2840///////////////////////////////////////////////////////////////////////////////
2841
reed3aafe112016-08-18 12:45:34 -07002842SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002843 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002844
2845 SkASSERT(canvas);
2846
reed3aafe112016-08-18 12:45:34 -07002847 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002848 fDone = !fImpl->next();
2849}
2850
2851SkCanvas::LayerIter::~LayerIter() {
2852 fImpl->~SkDrawIter();
2853}
2854
2855void SkCanvas::LayerIter::next() {
2856 fDone = !fImpl->next();
2857}
2858
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002859SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002860 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002861}
2862
2863const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002864 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002865}
2866
2867const SkPaint& SkCanvas::LayerIter::paint() const {
2868 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002869 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002870 paint = &fDefaultPaint;
2871 }
2872 return *paint;
2873}
2874
Mike Reeda1361362017-03-07 09:37:29 -05002875void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2876 return fImpl->fDevice->onAsRgnClip(rgn);
2877}
2878
reed@android.com8a1c16f2008-12-17 15:59:43 +00002879int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2880int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002881
2882///////////////////////////////////////////////////////////////////////////////
2883
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002884static bool supported_for_raster_canvas(const SkImageInfo& info) {
2885 switch (info.alphaType()) {
2886 case kPremul_SkAlphaType:
2887 case kOpaque_SkAlphaType:
2888 break;
2889 default:
2890 return false;
2891 }
2892
2893 switch (info.colorType()) {
2894 case kAlpha_8_SkColorType:
2895 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002896 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002897 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002898 break;
2899 default:
2900 return false;
2901 }
2902
2903 return true;
2904}
2905
Mike Reed5df49342016-11-12 08:06:55 -06002906std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002907 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002908 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002909 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002910 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002911
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002912 SkBitmap bitmap;
2913 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002914 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002915 }
Mike Reed12f77342017-11-08 11:19:52 -05002916
2917 return props ?
2918 skstd::make_unique<SkCanvas>(bitmap, *props) :
2919 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002920}
reedd5fa1a42014-08-09 11:08:05 -07002921
2922///////////////////////////////////////////////////////////////////////////////
2923
Florin Malitaee424ac2016-12-01 12:47:59 -05002924SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2925 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2926
Florin Malita439ace92016-12-02 12:05:41 -05002927SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2928 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2929
Florin Malitaee424ac2016-12-01 12:47:59 -05002930SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2931 (void)this->INHERITED::getSaveLayerStrategy(rec);
2932 return kNoLayer_SaveLayerStrategy;
2933}
2934
2935///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002936
reed73603f32016-09-20 08:42:38 -07002937static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2938static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2939static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2940static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2941static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2942static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002943
2944///////////////////////////////////////////////////////////////////////////////////////////////////
2945
2946SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2947 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002948 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002949 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2950 SkIPoint origin = dev->getOrigin();
2951 SkMatrix ctm = this->getTotalMatrix();
2952 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2953
2954 SkIRect clip = fMCRec->fRasterClip.getBounds();
2955 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002956 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002957 clip.setEmpty();
2958 }
2959
2960 fAllocator->updateHandle(handle, ctm, clip);
2961 return handle;
2962 }
2963 return nullptr;
2964}
2965
2966static bool install(SkBitmap* bm, const SkImageInfo& info,
2967 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002968 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002969}
2970
2971SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2972 SkBitmap* bm) {
2973 SkRasterHandleAllocator::Rec rec;
2974 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2975 return nullptr;
2976 }
2977 return rec.fHandle;
2978}
2979
2980std::unique_ptr<SkCanvas>
2981SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2982 const SkImageInfo& info, const Rec* rec) {
2983 if (!alloc || !supported_for_raster_canvas(info)) {
2984 return nullptr;
2985 }
2986
2987 SkBitmap bm;
2988 Handle hndl;
2989
2990 if (rec) {
2991 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2992 } else {
2993 hndl = alloc->allocBitmap(info, &bm);
2994 }
2995 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2996}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002997
2998///////////////////////////////////////////////////////////////////////////////////////////////////
2999
3000