blob: 269fac6f31a50e7ba698b0ea6ae6782e1981e924 [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.
Mike Reed19d7bd62018-02-19 14:10:57 -0500403 return imgCF->makeComposed(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
Mike Kleine083f7c2018-02-07 12:54:27 -05001039static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -05001040 // Need to force L32 for now if we have an image filter.
1041 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
1042 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -05001043 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -08001044 }
Mike Klein649fb732018-02-26 15:09:16 -05001045
1046 SkColorType ct = prev.colorType();
1047 if (prev.bytesPerPixel() <= 4) {
1048 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
1049 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
1050 ct = kN32_SkColorType;
1051 }
1052 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001053}
1054
reed4960eee2015-12-18 07:09:18 -08001055void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1056 const SkRect* bounds = rec.fBounds;
1057 const SkPaint* paint = rec.fPaint;
1058 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1059
reed8c30a812016-04-20 16:36:51 -07001060 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001061 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001062 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001063 SkMatrix remainder;
1064 SkSize scale;
1065 /*
1066 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1067 * but they do handle scaling. To accommodate this, we do the following:
1068 *
1069 * 1. Stash off the current CTM
1070 * 2. Decompose the CTM into SCALE and REMAINDER
1071 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1072 * contains the REMAINDER
1073 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1074 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1075 * of the original imagefilter, and draw that (via drawSprite)
1076 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1077 *
1078 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1079 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1080 */
reed96a04f32016-04-25 09:25:15 -07001081 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001082 stashedMatrix.decomposeScale(&scale, &remainder))
1083 {
1084 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1085 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1086 SkPaint* p = lazyP.set(*paint);
1087 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1088 SkFilterQuality::kLow_SkFilterQuality,
1089 sk_ref_sp(imageFilter)));
1090 imageFilter = p->getImageFilter();
1091 paint = p;
1092 }
reed8c30a812016-04-20 16:36:51 -07001093
junov@chromium.orga907ac32012-02-24 21:54:07 +00001094 // do this before we create the layer. We don't call the public save() since
1095 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001096 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001097
junov@chromium.orga907ac32012-02-24 21:54:07 +00001098 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001099 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001100 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101 }
1102
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001103 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1104 // the clipRectBounds() call above?
1105 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001106 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001107 }
1108
reed8dc0ccb2015-03-20 06:32:52 -07001109 SkPixelGeometry geo = fProps.pixelGeometry();
1110 if (paint) {
reed76033be2015-03-14 10:54:31 -07001111 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001112 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001113 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001114 }
1115 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001116
robertphillips5139e502016-07-19 05:10:40 -07001117 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001118 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001119 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001120 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001121 }
reedb2db8982014-11-13 12:41:02 -08001122
Mike Kleine083f7c2018-02-07 12:54:27 -05001123 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001124
Hal Canary704cd322016-11-07 14:13:52 -05001125 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001126 {
reed70ee31b2015-12-10 13:44:45 -08001127 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001128 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001129 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001130 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001131 preserveLCDText,
1132 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001133 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1134 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001135 return;
reed61f501f2015-04-29 08:34:00 -07001136 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001137 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001138 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001139
Mike Reedb43a3e02017-02-11 10:18:58 -05001140 // only have a "next" if this new layer doesn't affect the clip (rare)
1141 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142 fMCRec->fLayer = layer;
1143 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001144
Mike Reedc61abee2017-02-28 17:45:27 -05001145 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001146 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001147 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001148 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001149
Mike Reedc42a1cd2017-02-14 14:25:14 -05001150 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1151
1152 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1153 if (layer->fNext) {
1154 // need to punch a hole in the previous device, so we don't draw there, given that
1155 // the new top-layer will allow drawing to happen "below" it.
1156 SkRegion hole(ir);
1157 do {
1158 layer = layer->fNext;
1159 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1160 } while (layer->fNext);
1161 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001162}
1163
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001164int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001165 if (0xFF == alpha) {
1166 return this->saveLayer(bounds, nullptr);
1167 } else {
1168 SkPaint tmpPaint;
1169 tmpPaint.setAlpha(alpha);
1170 return this->saveLayer(bounds, &tmpPaint);
1171 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001172}
1173
reed@android.com8a1c16f2008-12-17 15:59:43 +00001174void SkCanvas::internalRestore() {
1175 SkASSERT(fMCStack.count() != 0);
1176
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001177 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001178 DeviceCM* layer = fMCRec->fLayer; // may be null
1179 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001180 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181
1182 // now do the normal restore()
1183 fMCRec->~MCRec(); // balanced in save()
1184 fMCStack.pop_back();
1185 fMCRec = (MCRec*)fMCStack.back();
1186
Mike Reedc42a1cd2017-02-14 14:25:14 -05001187 if (fMCRec) {
1188 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1189 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001190
reed@android.com8a1c16f2008-12-17 15:59:43 +00001191 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1192 since if we're being recorded, we don't want to record this (the
1193 recorder will have already recorded the restore).
1194 */
bsalomon49f085d2014-09-05 13:34:00 -07001195 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001196 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001197 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001198 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001199 layer->fPaint.get(),
1200 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001201 // restore what we smashed in internalSaveLayer
1202 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001203 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001204 delete layer;
reedb679ca82015-04-07 04:40:48 -07001205 } else {
1206 // we're at the root
reeda499f902015-05-01 09:34:31 -07001207 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001208 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001209 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001211 }
msarettfbfa2582016-08-12 08:29:08 -07001212
1213 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001214 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001215 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1216 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217}
1218
reede8f30622016-03-23 18:59:25 -07001219sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001220 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001221 props = &fProps;
1222 }
1223 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001224}
1225
reede8f30622016-03-23 18:59:25 -07001226sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001227 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001228 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001229}
1230
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001231SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001232 return this->onImageInfo();
1233}
1234
1235SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001236 SkBaseDevice* dev = this->getDevice();
1237 if (dev) {
1238 return dev->imageInfo();
1239 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001240 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001241 }
1242}
1243
brianosman898235c2016-04-06 07:38:23 -07001244bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001245 return this->onGetProps(props);
1246}
1247
1248bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001249 SkBaseDevice* dev = this->getDevice();
1250 if (dev) {
1251 if (props) {
1252 *props = fProps;
1253 }
1254 return true;
1255 } else {
1256 return false;
1257 }
1258}
1259
reed6ceeebd2016-03-09 14:26:26 -08001260bool SkCanvas::peekPixels(SkPixmap* pmap) {
1261 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001262}
1263
reed884e97c2015-05-26 11:31:54 -07001264bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001265 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001266 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001267}
1268
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001269void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001270 SkPixmap pmap;
1271 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001272 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001273 }
1274 if (info) {
1275 *info = pmap.info();
1276 }
1277 if (rowBytes) {
1278 *rowBytes = pmap.rowBytes();
1279 }
1280 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001281 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001282 }
reed884e97c2015-05-26 11:31:54 -07001283 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001284}
1285
reed884e97c2015-05-26 11:31:54 -07001286bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001287 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001288 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001289}
1290
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001292
Florin Malita53f77bd2017-04-28 13:48:37 -04001293void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1294 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001296 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297 paint = &tmp;
1298 }
reed@google.com4b226022011-01-11 18:32:13 +00001299
reed@google.com8926b162012-03-23 15:36:36 +00001300 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001301
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001303 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001304 paint = &looper.paint();
1305 SkImageFilter* filter = paint->getImageFilter();
1306 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001307 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001308 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1309 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001310 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1311 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001312 }
reed@google.com76dd2772012-01-05 21:15:07 +00001313 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001314 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001315 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001316 }
reeda2217ef2016-07-20 06:04:34 -07001317
reed@google.com4e2b3d32011-04-07 14:18:59 +00001318 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319}
1320
reed32704672015-12-16 08:27:10 -08001321/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001322
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001323void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001324 if (dx || dy) {
1325 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001326 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001327
reedfe69b502016-09-12 06:31:48 -07001328 // Translate shouldn't affect the is-scale-translateness of the matrix.
1329 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001330
Mike Reedc42a1cd2017-02-14 14:25:14 -05001331 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001332
reedfe69b502016-09-12 06:31:48 -07001333 this->didTranslate(dx,dy);
1334 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335}
1336
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001337void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001338 SkMatrix m;
1339 m.setScale(sx, sy);
1340 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341}
1342
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001343void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001344 SkMatrix m;
1345 m.setRotate(degrees);
1346 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001347}
1348
bungeman7438bfc2016-07-12 15:01:19 -07001349void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1350 SkMatrix m;
1351 m.setRotate(degrees, px, py);
1352 this->concat(m);
1353}
1354
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001355void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001356 SkMatrix m;
1357 m.setSkew(sx, sy);
1358 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001359}
1360
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001361void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001362 if (matrix.isIdentity()) {
1363 return;
1364 }
1365
reed2ff1fce2014-12-11 07:07:37 -08001366 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001367 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001368 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001369
Mike Reed7627fa52017-02-08 10:07:53 -05001370 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001371
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001372 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001373}
1374
reed8c30a812016-04-20 16:36:51 -07001375void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001376 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001377 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001378
Mike Reedc42a1cd2017-02-14 14:25:14 -05001379 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001380}
1381
1382void SkCanvas::setMatrix(const SkMatrix& matrix) {
1383 this->checkForDeferredSave();
1384 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001385 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386}
1387
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001389 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001390}
1391
1392//////////////////////////////////////////////////////////////////////////////
1393
Mike Reedc1f77742016-12-09 09:00:50 -05001394void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001395 if (!rect.isFinite()) {
1396 return;
1397 }
reed2ff1fce2014-12-11 07:07:37 -08001398 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001399 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1400 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001401}
1402
Mike Reedc1f77742016-12-09 09:00:50 -05001403void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001404 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001405
Mike Reed7627fa52017-02-08 10:07:53 -05001406 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001407
reedc64eff52015-11-21 12:39:45 -08001408 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001409 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1410 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001411 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412}
1413
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001414void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1415 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001416 if (fClipRestrictionRect.isEmpty()) {
1417 // we notify the device, but we *dont* resolve deferred saves (since we're just
1418 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001419 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001420 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001421 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001422 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001423 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001424 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001425 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1426 }
1427}
1428
Mike Reedc1f77742016-12-09 09:00:50 -05001429void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001430 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001431 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001432 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001433 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1434 } else {
1435 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001436 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001438
Mike Reedc1f77742016-12-09 09:00:50 -05001439void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001440 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001441
Brian Salomona3b45d42016-10-03 11:36:16 -04001442 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001443
Mike Reed7627fa52017-02-08 10:07:53 -05001444 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001445
Mike Reed20800c82017-11-15 16:09:04 -05001446 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1447 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001448 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001449}
1450
Mike Reedc1f77742016-12-09 09:00:50 -05001451void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001452 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001453 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001454
1455 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1456 SkRect r;
1457 if (path.isRect(&r)) {
1458 this->onClipRect(r, op, edgeStyle);
1459 return;
1460 }
1461 SkRRect rrect;
1462 if (path.isOval(&r)) {
1463 rrect.setOval(r);
1464 this->onClipRRect(rrect, op, edgeStyle);
1465 return;
1466 }
1467 if (path.isRRect(&rrect)) {
1468 this->onClipRRect(rrect, op, edgeStyle);
1469 return;
1470 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001471 }
robertphillips39f05382015-11-24 09:30:12 -08001472
1473 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001474}
1475
Mike Reedc1f77742016-12-09 09:00:50 -05001476void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001477 AutoValidateClip avc(this);
1478
Brian Salomona3b45d42016-10-03 11:36:16 -04001479 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001480
Mike Reed7627fa52017-02-08 10:07:53 -05001481 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482
Brian Salomona3b45d42016-10-03 11:36:16 -04001483 const SkPath* rasterClipPath = &path;
1484 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001485 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1486 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001487 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488}
1489
Mike Reedc1f77742016-12-09 09:00:50 -05001490void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001491 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001492 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001493}
1494
Mike Reedc1f77742016-12-09 09:00:50 -05001495void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001496 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001497
reed@google.com5c3d1472011-02-22 19:12:23 +00001498 AutoValidateClip avc(this);
1499
Mike Reed20800c82017-11-15 16:09:04 -05001500 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001501 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001502}
1503
reed@google.com819c9212011-02-23 18:56:55 +00001504#ifdef SK_DEBUG
1505void SkCanvas::validateClip() const {
1506 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001507 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001508 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001509 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001510 return;
1511 }
reed@google.com819c9212011-02-23 18:56:55 +00001512}
1513#endif
1514
Mike Reeda1361362017-03-07 09:37:29 -05001515bool SkCanvas::androidFramework_isClipAA() const {
1516 bool containsAA = false;
1517
1518 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1519
1520 return containsAA;
1521}
1522
1523class RgnAccumulator {
1524 SkRegion* fRgn;
1525public:
1526 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1527 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1528 SkIPoint origin = device->getOrigin();
1529 if (origin.x() | origin.y()) {
1530 rgn->translate(origin.x(), origin.y());
1531 }
1532 fRgn->op(*rgn, SkRegion::kUnion_Op);
1533 }
1534};
1535
1536void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1537 RgnAccumulator accum(rgn);
1538 SkRegion tmp;
1539
1540 rgn->setEmpty();
1541 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001542}
1543
reed@google.com5c3d1472011-02-22 19:12:23 +00001544///////////////////////////////////////////////////////////////////////////////
1545
reed@google.com754de5f2014-02-24 19:38:20 +00001546bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001547 return fMCRec->fRasterClip.isEmpty();
1548
1549 // TODO: should we only use the conservative answer in a recording canvas?
1550#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001551 SkBaseDevice* dev = this->getTopDevice();
1552 // if no device we return true
1553 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001554#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001555}
1556
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001557bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001558 SkBaseDevice* dev = this->getTopDevice();
1559 // if no device we return false
1560 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001561}
1562
msarettfbfa2582016-08-12 08:29:08 -07001563static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1564#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1565 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1566 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1567 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1568 return 0xF != _mm_movemask_ps(mask);
1569#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1570 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1571 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1572 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1573 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1574#else
1575 SkRect devRectAsRect;
1576 SkRect devClipAsRect;
1577 devRect.store(&devRectAsRect.fLeft);
1578 devClip.store(&devClipAsRect.fLeft);
1579 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1580#endif
1581}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001582
msarettfbfa2582016-08-12 08:29:08 -07001583// It's important for this function to not be inlined. Otherwise the compiler will share code
1584// between the fast path and the slow path, resulting in two slow paths.
1585static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1586 const SkMatrix& matrix) {
1587 SkRect deviceRect;
1588 matrix.mapRect(&deviceRect, src);
1589 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1590}
1591
1592bool SkCanvas::quickReject(const SkRect& src) const {
1593#ifdef SK_DEBUG
1594 // Verify that fDeviceClipBounds are set properly.
1595 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001596 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001597 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001598 } else {
msarettfbfa2582016-08-12 08:29:08 -07001599 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001600 }
msarettfbfa2582016-08-12 08:29:08 -07001601
msarett9637ea92016-08-18 14:03:30 -07001602 // Verify that fIsScaleTranslate is set properly.
1603 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001604#endif
1605
msarett9637ea92016-08-18 14:03:30 -07001606 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001607 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1608 }
1609
1610 // We inline the implementation of mapScaleTranslate() for the fast path.
1611 float sx = fMCRec->fMatrix.getScaleX();
1612 float sy = fMCRec->fMatrix.getScaleY();
1613 float tx = fMCRec->fMatrix.getTranslateX();
1614 float ty = fMCRec->fMatrix.getTranslateY();
1615 Sk4f scale(sx, sy, sx, sy);
1616 Sk4f trans(tx, ty, tx, ty);
1617
1618 // Apply matrix.
1619 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1620
1621 // Make sure left < right, top < bottom.
1622 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1623 Sk4f min = Sk4f::Min(ltrb, rblt);
1624 Sk4f max = Sk4f::Max(ltrb, rblt);
1625 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1626 // ARM this sequence generates the fastest (a single instruction).
1627 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1628
1629 // Check if the device rect is NaN or outside the clip.
1630 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001631}
1632
reed@google.com3b3e8952012-08-16 20:53:31 +00001633bool SkCanvas::quickReject(const SkPath& path) const {
1634 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001635}
1636
Mike Klein83c8dd92017-11-28 17:08:45 -05001637SkRect SkCanvas::getLocalClipBounds() const {
1638 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001639 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001640 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641 }
1642
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001643 SkMatrix inverse;
1644 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001645 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001646 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001647 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648
Mike Reed42e8c532017-01-23 14:09:13 -05001649 SkRect bounds;
1650 SkRect r;
1651 // adjust it outwards in case we are antialiasing
1652 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001653
Mike Reed42e8c532017-01-23 14:09:13 -05001654 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1655 ibounds.fRight + inset, ibounds.fBottom + inset);
1656 inverse.mapRect(&bounds, r);
1657 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658}
1659
Mike Klein83c8dd92017-11-28 17:08:45 -05001660SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001661 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001662}
1663
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001665 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001666}
1667
Brian Osman11052242016-10-27 14:47:55 -04001668GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001669 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001670 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001671}
1672
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001673GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001674 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001675 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001676}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001677
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001678void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1679 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001680 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001681 if (outer.isEmpty()) {
1682 return;
1683 }
1684 if (inner.isEmpty()) {
1685 this->drawRRect(outer, paint);
1686 return;
1687 }
1688
1689 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001690 // be able to return ...
1691 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001692 //
1693 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001694 if (!outer.getBounds().contains(inner.getBounds())) {
1695 return;
1696 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001697
1698 this->onDrawDRRect(outer, inner, paint);
1699}
1700
reed41af9662015-01-05 07:49:08 -08001701void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001702 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001703 this->onDrawPaint(paint);
1704}
1705
1706void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001707 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001708 // To avoid redundant logic in our culling code and various backends, we always sort rects
1709 // before passing them along.
1710 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001711}
1712
msarettdca352e2016-08-26 06:37:45 -07001713void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001714 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001715 if (region.isEmpty()) {
1716 return;
1717 }
1718
1719 if (region.isRect()) {
1720 return this->drawIRect(region.getBounds(), paint);
1721 }
1722
1723 this->onDrawRegion(region, paint);
1724}
1725
reed41af9662015-01-05 07:49:08 -08001726void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001727 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001728 // To avoid redundant logic in our culling code and various backends, we always sort rects
1729 // before passing them along.
1730 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001731}
1732
1733void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001734 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001735 this->onDrawRRect(rrect, paint);
1736}
1737
1738void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001739 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001740 this->onDrawPoints(mode, count, pts, paint);
1741}
1742
Mike Reede88a1cb2017-03-17 09:50:46 -04001743void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1744 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001745 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001746 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001747 this->onDrawVerticesObject(vertices.get(), mode, paint);
1748}
1749
1750void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001751 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001752 RETURN_ON_NULL(vertices);
1753 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001754}
1755
1756void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001757 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001758 this->onDrawPath(path, paint);
1759}
1760
reeda85d4d02015-05-06 12:56:48 -07001761void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001762 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001763 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001764 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001765}
1766
Mike Reedc4e31092018-01-30 11:15:27 -05001767// Returns true if the rect can be "filled" : non-empty and finite
1768static bool fillable(const SkRect& r) {
1769 SkScalar w = r.width();
1770 SkScalar h = r.height();
1771 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1772}
1773
reede47829b2015-08-06 10:02:53 -07001774void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1775 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001776 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001777 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001778 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001779 return;
1780 }
1781 this->onDrawImageRect(image, &src, dst, paint, constraint);
1782}
reed41af9662015-01-05 07:49:08 -08001783
reed84984ef2015-07-17 07:09:43 -07001784void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1785 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001786 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001787 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001788}
1789
reede47829b2015-08-06 10:02:53 -07001790void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1791 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001792 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001793 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1794 constraint);
1795}
reede47829b2015-08-06 10:02:53 -07001796
reed4c21dc52015-06-25 12:32:03 -07001797void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1798 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001799 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001800 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001801 if (dst.isEmpty()) {
1802 return;
1803 }
msarett552bca92016-08-03 06:53:26 -07001804 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1805 this->onDrawImageNine(image, center, dst, paint);
1806 } else {
reede47829b2015-08-06 10:02:53 -07001807 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001808 }
reed4c21dc52015-06-25 12:32:03 -07001809}
1810
msarett16882062016-08-16 09:31:08 -07001811void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1812 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001813 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001814 RETURN_ON_NULL(image);
1815 if (dst.isEmpty()) {
1816 return;
1817 }
msarett71df2d72016-09-30 12:41:42 -07001818
1819 SkIRect bounds;
1820 Lattice latticePlusBounds = lattice;
1821 if (!latticePlusBounds.fBounds) {
1822 bounds = SkIRect::MakeWH(image->width(), image->height());
1823 latticePlusBounds.fBounds = &bounds;
1824 }
1825
1826 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1827 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001828 } else {
1829 this->drawImageRect(image, dst, paint);
1830 }
1831}
1832
reed41af9662015-01-05 07:49:08 -08001833void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001834 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001835 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001836 return;
1837 }
reed41af9662015-01-05 07:49:08 -08001838 this->onDrawBitmap(bitmap, dx, dy, paint);
1839}
1840
reede47829b2015-08-06 10:02:53 -07001841void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001842 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001843 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001844 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001845 return;
1846 }
reede47829b2015-08-06 10:02:53 -07001847 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001848}
1849
reed84984ef2015-07-17 07:09:43 -07001850void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1851 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001852 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001853}
1854
reede47829b2015-08-06 10:02:53 -07001855void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1856 SrcRectConstraint constraint) {
1857 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1858 constraint);
1859}
reede47829b2015-08-06 10:02:53 -07001860
reed41af9662015-01-05 07:49:08 -08001861void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1862 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001863 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001864 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001865 return;
1866 }
msarett552bca92016-08-03 06:53:26 -07001867 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1868 this->onDrawBitmapNine(bitmap, center, dst, paint);
1869 } else {
reeda5517e22015-07-14 10:54:12 -07001870 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001871 }
reed41af9662015-01-05 07:49:08 -08001872}
1873
msarettc573a402016-08-02 08:05:56 -07001874void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1875 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001876 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001877 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001878 return;
1879 }
msarett71df2d72016-09-30 12:41:42 -07001880
1881 SkIRect bounds;
1882 Lattice latticePlusBounds = lattice;
1883 if (!latticePlusBounds.fBounds) {
1884 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1885 latticePlusBounds.fBounds = &bounds;
1886 }
1887
1888 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1889 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001890 } else {
msarett16882062016-08-16 09:31:08 -07001891 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001892 }
msarettc573a402016-08-02 08:05:56 -07001893}
1894
reed71c3c762015-06-24 10:29:17 -07001895void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001896 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001897 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001898 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001899 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001900 if (count <= 0) {
1901 return;
1902 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001903 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001904 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001905 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001906}
1907
reedf70b5312016-03-04 16:36:20 -08001908void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001909 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001910 if (key) {
1911 this->onDrawAnnotation(rect, key, value);
1912 }
1913}
1914
reede47829b2015-08-06 10:02:53 -07001915void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1916 const SkPaint* paint, SrcRectConstraint constraint) {
1917 if (src) {
1918 this->drawImageRect(image, *src, dst, paint, constraint);
1919 } else {
1920 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1921 dst, paint, constraint);
1922 }
1923}
1924void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1925 const SkPaint* paint, SrcRectConstraint constraint) {
1926 if (src) {
1927 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1928 } else {
1929 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1930 dst, paint, constraint);
1931 }
1932}
1933
Mike Reed4204da22017-05-17 08:53:36 -04001934void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001935 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001936 this->onDrawShadowRec(path, rec);
1937}
1938
1939void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1940 SkPaint paint;
1941 const SkRect& pathBounds = path.getBounds();
1942
1943 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1944 while (iter.next()) {
1945 iter.fDevice->drawShadow(path, rec);
1946 }
1947 LOOPER_END
1948}
1949
reed@android.com8a1c16f2008-12-17 15:59:43 +00001950//////////////////////////////////////////////////////////////////////////////
1951// These are the virtual drawing methods
1952//////////////////////////////////////////////////////////////////////////////
1953
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001954void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001955 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001956 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1957 }
1958}
1959
reed41af9662015-01-05 07:49:08 -08001960void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001961 this->internalDrawPaint(paint);
1962}
1963
1964void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001965 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001966
1967 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001968 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001969 }
1970
reed@google.com4e2b3d32011-04-07 14:18:59 +00001971 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001972}
1973
reed41af9662015-01-05 07:49:08 -08001974void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1975 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001976 if ((long)count <= 0) {
1977 return;
1978 }
1979
Mike Reed822128b2017-02-28 16:41:03 -05001980 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001981 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001982 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001983 // special-case 2 points (common for drawing a single line)
1984 if (2 == count) {
1985 r.set(pts[0], pts[1]);
1986 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001987 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001988 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001989 if (!r.isFinite()) {
1990 return;
1991 }
Mike Reed822128b2017-02-28 16:41:03 -05001992 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001993 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1994 return;
1995 }
1996 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001997 }
reed@google.coma584aed2012-05-16 14:06:02 +00001998
halcanary96fcdcc2015-08-27 07:41:13 -07001999 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002000
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002001 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002002
reed@android.com8a1c16f2008-12-17 15:59:43 +00002003 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002004 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002005 }
reed@google.com4b226022011-01-11 18:32:13 +00002006
reed@google.com4e2b3d32011-04-07 14:18:59 +00002007 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002008}
2009
reed4a167172016-08-18 17:15:25 -07002010static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2011 return ((intptr_t)paint.getImageFilter() |
2012#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2013 (intptr_t)canvas->getDrawFilter() |
2014#endif
2015 (intptr_t)paint.getLooper() ) != 0;
2016}
2017
reed41af9662015-01-05 07:49:08 -08002018void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002019 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002020 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002021 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002022 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002023 return;
2024 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002025 }
reed@google.com4b226022011-01-11 18:32:13 +00002026
reed4a167172016-08-18 17:15:25 -07002027 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002028 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002029
reed4a167172016-08-18 17:15:25 -07002030 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002031 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002032 }
2033
2034 LOOPER_END
2035 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002036 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002037 SkDrawIter iter(this);
2038 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002039 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002040 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002041 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002042}
2043
msarett44df6512016-08-25 13:54:30 -07002044void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002045 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002046 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002047 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002048 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2049 return;
2050 }
msarett44df6512016-08-25 13:54:30 -07002051 }
2052
Mike Reed822128b2017-02-28 16:41:03 -05002053 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002054
2055 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002056 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002057 }
2058
2059 LOOPER_END
2060}
2061
reed41af9662015-01-05 07:49:08 -08002062void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002063 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002064 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002065 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002066 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002067 return;
2068 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002069 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002070
Mike Reed822128b2017-02-28 16:41:03 -05002071 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002072
2073 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002074 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002075 }
2076
2077 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002078}
2079
bsalomonac3aa242016-08-19 11:25:19 -07002080void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2081 SkScalar sweepAngle, bool useCenter,
2082 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002083 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002084 if (paint.canComputeFastBounds()) {
2085 SkRect storage;
2086 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002087 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002088 return;
2089 }
bsalomonac3aa242016-08-19 11:25:19 -07002090 }
2091
Mike Reed822128b2017-02-28 16:41:03 -05002092 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002093
2094 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002095 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002096 }
2097
2098 LOOPER_END
2099}
2100
reed41af9662015-01-05 07:49:08 -08002101void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002102 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002103 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002104 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2105 return;
2106 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002107 }
2108
2109 if (rrect.isRect()) {
2110 // call the non-virtual version
2111 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002112 return;
2113 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002114 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002115 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2116 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002117 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002118
Mike Reed822128b2017-02-28 16:41:03 -05002119 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002120
2121 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002122 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002123 }
2124
2125 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002126}
2127
Mike Reed822128b2017-02-28 16:41:03 -05002128void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002129 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002130 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002131 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2132 return;
2133 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002134 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002135
Mike Reed822128b2017-02-28 16:41:03 -05002136 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002137
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002138 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002139 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002140 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002141
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002142 LOOPER_END
2143}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002144
reed41af9662015-01-05 07:49:08 -08002145void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002146 if (!path.isFinite()) {
2147 return;
2148 }
2149
Mike Reed822128b2017-02-28 16:41:03 -05002150 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002151 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002152 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002153 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2154 return;
2155 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002156 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002157
Mike Reed822128b2017-02-28 16:41:03 -05002158 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002159 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002160 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002161 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002162 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002163 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002164
Mike Reed822128b2017-02-28 16:41:03 -05002165 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002166
2167 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002168 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002169 }
2170
reed@google.com4e2b3d32011-04-07 14:18:59 +00002171 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002172}
2173
reed262a71b2015-12-05 13:07:27 -08002174bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002175 if (!paint.getImageFilter()) {
2176 return false;
2177 }
2178
2179 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002180 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002181 return false;
2182 }
2183
2184 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2185 // Once we can filter and the filter will return a result larger than itself, we should be
2186 // able to remove this constraint.
2187 // skbug.com/4526
2188 //
2189 SkPoint pt;
2190 ctm.mapXY(x, y, &pt);
2191 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2192 return ir.contains(fMCRec->fRasterClip.getBounds());
2193}
2194
reeda85d4d02015-05-06 12:56:48 -07002195void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07002196 SkRect bounds = SkRect::MakeXYWH(x, y,
2197 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002198 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002199 SkRect tmp = bounds;
2200 if (paint) {
2201 paint->computeFastBounds(tmp, &tmp);
2202 }
2203 if (this->quickReject(tmp)) {
2204 return;
2205 }
reeda85d4d02015-05-06 12:56:48 -07002206 }
halcanary9d524f22016-03-29 09:03:52 -07002207
reeda85d4d02015-05-06 12:56:48 -07002208 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002209 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002210 paint = lazy.init();
2211 }
reed262a71b2015-12-05 13:07:27 -08002212
reeda2217ef2016-07-20 06:04:34 -07002213 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002214 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2215 *paint);
2216 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002217 special = this->getDevice()->makeSpecial(image);
2218 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002219 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002220 }
2221 }
2222
reed262a71b2015-12-05 13:07:27 -08002223 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2224
reeda85d4d02015-05-06 12:56:48 -07002225 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002226 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002227 if (special) {
2228 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002229 iter.fDevice->ctm().mapXY(x, y, &pt);
2230 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002231 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002232 SkScalarRoundToInt(pt.fY), pnt,
2233 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002234 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002235 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002236 }
reeda85d4d02015-05-06 12:56:48 -07002237 }
halcanary9d524f22016-03-29 09:03:52 -07002238
reeda85d4d02015-05-06 12:56:48 -07002239 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002240}
2241
reed41af9662015-01-05 07:49:08 -08002242void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002243 const SkPaint* paint, SrcRectConstraint constraint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002244 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002245 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002246 if (paint) {
2247 paint->computeFastBounds(dst, &storage);
2248 }
2249 if (this->quickReject(storage)) {
2250 return;
2251 }
reeda85d4d02015-05-06 12:56:48 -07002252 }
2253 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002254 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002255 paint = lazy.init();
2256 }
halcanary9d524f22016-03-29 09:03:52 -07002257
senorblancoc41e7e12015-12-07 12:51:30 -08002258 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002259 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002260
reeda85d4d02015-05-06 12:56:48 -07002261 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002262 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002263 }
halcanary9d524f22016-03-29 09:03:52 -07002264
reeda85d4d02015-05-06 12:56:48 -07002265 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002266}
2267
reed41af9662015-01-05 07:49:08 -08002268void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002269 SkDEBUGCODE(bitmap.validate();)
2270
reed33366972015-10-08 09:22:02 -07002271 if (bitmap.drawsNothing()) {
2272 return;
2273 }
2274
2275 SkLazyPaint lazy;
2276 if (nullptr == paint) {
2277 paint = lazy.init();
2278 }
2279
Mike Reed822128b2017-02-28 16:41:03 -05002280 SkRect bounds;
2281 bitmap.getBounds(&bounds);
2282 bounds.offset(x, y);
2283 bool canFastBounds = paint->canComputeFastBounds();
2284 if (canFastBounds) {
2285 SkRect storage;
2286 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002287 return;
2288 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002289 }
reed@google.com4b226022011-01-11 18:32:13 +00002290
reeda2217ef2016-07-20 06:04:34 -07002291 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002292 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2293 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002294 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002295 special = this->getDevice()->makeSpecial(bitmap);
2296 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002297 drawAsSprite = false;
2298 }
2299 }
2300
Mike Reed822128b2017-02-28 16:41:03 -05002301 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002302
2303 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002304 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002305 if (special) {
reed262a71b2015-12-05 13:07:27 -08002306 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002307 iter.fDevice->ctm().mapXY(x, y, &pt);
2308 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002309 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002310 SkScalarRoundToInt(pt.fY), pnt,
2311 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002312 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002313 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002314 }
reed33366972015-10-08 09:22:02 -07002315 }
msarettfbfa2582016-08-12 08:29:08 -07002316
reed33366972015-10-08 09:22:02 -07002317 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318}
2319
reed@google.com9987ec32011-09-07 11:57:52 +00002320// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002321void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002322 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002323 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002324 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002325 return;
2326 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002327
halcanary96fcdcc2015-08-27 07:41:13 -07002328 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002329 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002330 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2331 return;
2332 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002333 }
reed@google.com3d608122011-11-21 15:16:16 +00002334
reed@google.com33535f32012-09-25 15:37:50 +00002335 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002336 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002337 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002338 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002339
senorblancoc41e7e12015-12-07 12:51:30 -08002340 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002341 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002342
reed@google.com33535f32012-09-25 15:37:50 +00002343 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002344 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002345 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002346
reed@google.com33535f32012-09-25 15:37:50 +00002347 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002348}
2349
reed41af9662015-01-05 07:49:08 -08002350void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002351 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002352 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002353 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002354}
2355
reed4c21dc52015-06-25 12:32:03 -07002356void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2357 const SkPaint* paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002358 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002359 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002360 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2361 return;
2362 }
reed@google.com3d608122011-11-21 15:16:16 +00002363 }
halcanary9d524f22016-03-29 09:03:52 -07002364
reed4c21dc52015-06-25 12:32:03 -07002365 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002366 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002367 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002368 }
halcanary9d524f22016-03-29 09:03:52 -07002369
senorblancoc41e7e12015-12-07 12:51:30 -08002370 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002371
reed4c21dc52015-06-25 12:32:03 -07002372 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002373 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002374 }
halcanary9d524f22016-03-29 09:03:52 -07002375
reed4c21dc52015-06-25 12:32:03 -07002376 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002377}
2378
reed41af9662015-01-05 07:49:08 -08002379void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2380 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002381 SkDEBUGCODE(bitmap.validate();)
2382
halcanary96fcdcc2015-08-27 07:41:13 -07002383 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002384 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002385 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2386 return;
2387 }
reed4c21dc52015-06-25 12:32:03 -07002388 }
halcanary9d524f22016-03-29 09:03:52 -07002389
reed4c21dc52015-06-25 12:32:03 -07002390 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002391 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002392 paint = lazy.init();
2393 }
halcanary9d524f22016-03-29 09:03:52 -07002394
senorblancoc41e7e12015-12-07 12:51:30 -08002395 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002396
reed4c21dc52015-06-25 12:32:03 -07002397 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002398 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002399 }
halcanary9d524f22016-03-29 09:03:52 -07002400
reed4c21dc52015-06-25 12:32:03 -07002401 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002402}
2403
msarett16882062016-08-16 09:31:08 -07002404void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2405 const SkPaint* paint) {
2406 if (nullptr == paint || paint->canComputeFastBounds()) {
2407 SkRect storage;
2408 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2409 return;
2410 }
2411 }
2412
2413 SkLazyPaint lazy;
2414 if (nullptr == paint) {
2415 paint = lazy.init();
2416 }
2417
2418 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2419
2420 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002421 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002422 }
2423
2424 LOOPER_END
2425}
2426
2427void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2428 const SkRect& dst, const SkPaint* paint) {
2429 if (nullptr == paint || paint->canComputeFastBounds()) {
2430 SkRect storage;
2431 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2432 return;
2433 }
2434 }
2435
2436 SkLazyPaint lazy;
2437 if (nullptr == paint) {
2438 paint = lazy.init();
2439 }
2440
2441 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2442
2443 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002444 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002445 }
2446
2447 LOOPER_END
2448}
2449
reed@google.comf67e4cf2011-03-15 20:56:58 +00002450class SkDeviceFilteredPaint {
2451public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002452 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002453 uint32_t filteredFlags = device->filterTextFlags(paint);
2454 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002455 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002456 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002457 fPaint = newPaint;
2458 } else {
2459 fPaint = &paint;
2460 }
2461 }
2462
reed@google.comf67e4cf2011-03-15 20:56:58 +00002463 const SkPaint& paint() const { return *fPaint; }
2464
2465private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002466 const SkPaint* fPaint;
2467 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002468};
2469
reed@google.come0d9ce82014-04-23 04:00:17 +00002470void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2471 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002472 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473
2474 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002475 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002476 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002477 }
2478
reed@google.com4e2b3d32011-04-07 14:18:59 +00002479 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480}
2481
reed@google.come0d9ce82014-04-23 04:00:17 +00002482void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2483 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002484 SkPoint textOffset = SkPoint::Make(0, 0);
2485
halcanary96fcdcc2015-08-27 07:41:13 -07002486 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002487
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002489 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002490 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002491 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002492 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002493
reed@google.com4e2b3d32011-04-07 14:18:59 +00002494 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002495}
2496
reed@google.come0d9ce82014-04-23 04:00:17 +00002497void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2498 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002499
2500 SkPoint textOffset = SkPoint::Make(0, constY);
2501
halcanary96fcdcc2015-08-27 07:41:13 -07002502 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002503
reed@android.com8a1c16f2008-12-17 15:59:43 +00002504 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002505 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002506 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002507 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002508 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002509
reed@google.com4e2b3d32011-04-07 14:18:59 +00002510 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002511}
2512
reed@google.come0d9ce82014-04-23 04:00:17 +00002513void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2514 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002515 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002516
reed@android.com8a1c16f2008-12-17 15:59:43 +00002517 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002518 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002519 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002520 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002521
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002522 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002523}
2524
reed45561a02016-07-07 12:47:17 -07002525void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2526 const SkRect* cullRect, const SkPaint& paint) {
2527 if (cullRect && this->quickReject(*cullRect)) {
2528 return;
2529 }
2530
2531 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2532
2533 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002534 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002535 }
2536
2537 LOOPER_END
2538}
2539
fmalita00d5c2c2014-08-21 08:53:26 -07002540void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2541 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002542
fmalita85d5eb92015-03-04 11:20:12 -08002543 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002544 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002545 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002546 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002547 SkRect tmp;
2548 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2549 return;
2550 }
2551 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002552 }
2553
fmalita024f9962015-03-03 19:08:17 -08002554 // We cannot filter in the looper as we normally do, because the paint is
2555 // incomplete at this point (text-related attributes are embedded within blob run paints).
2556 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002557 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002558
fmalita85d5eb92015-03-04 11:20:12 -08002559 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002560
fmalitaaa1b9122014-08-28 14:32:24 -07002561 while (iter.next()) {
2562 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002563 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002564 }
2565
fmalitaaa1b9122014-08-28 14:32:24 -07002566 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002567
2568 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002569}
2570
Cary Clark2a475ea2017-04-28 15:35:12 -04002571void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2572 this->drawText(string.c_str(), string.size(), x, y, paint);
2573}
2574
reed@google.come0d9ce82014-04-23 04:00:17 +00002575// These will become non-virtual, so they always call the (virtual) onDraw... method
2576void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2577 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002578 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002579 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002580 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002581 this->onDrawText(text, byteLength, x, y, paint);
2582 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002583}
2584void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2585 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002586 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002587 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002588 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002589 this->onDrawPosText(text, byteLength, pos, paint);
2590 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002591}
2592void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2593 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002594 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002595 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002596 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002597 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2598 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002599}
2600void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2601 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002602 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002603 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002604 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002605 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2606 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002607}
reed45561a02016-07-07 12:47:17 -07002608void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2609 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002610 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002611 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002612 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002613 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2614 }
2615}
fmalita00d5c2c2014-08-21 08:53:26 -07002616void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2617 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002618 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002619 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002620 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002621 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002622}
reed@google.come0d9ce82014-04-23 04:00:17 +00002623
Mike Reede88a1cb2017-03-17 09:50:46 -04002624void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2625 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002626 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2627
2628 while (iter.next()) {
2629 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002630 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002631 }
2632
2633 LOOPER_END
2634}
2635
dandovb3c9d1c2014-08-12 08:34:29 -07002636void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002637 const SkPoint texCoords[4], SkBlendMode bmode,
2638 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002639 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002640 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002641 return;
2642 }
mtklein6cfa73a2014-08-13 13:33:49 -07002643
Mike Reedfaba3712016-11-03 14:45:31 -04002644 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002645}
2646
2647void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002648 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002649 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002650 // Since a patch is always within the convex hull of the control points, we discard it when its
2651 // bounding rectangle is completely outside the current clip.
2652 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002653 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002654 if (this->quickReject(bounds)) {
2655 return;
2656 }
mtklein6cfa73a2014-08-13 13:33:49 -07002657
Mike Reed435071e2017-05-23 11:22:56 -04002658 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2659
halcanary96fcdcc2015-08-27 07:41:13 -07002660 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002661
dandovecfff212014-08-04 10:02:00 -07002662 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002663 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002664 }
mtklein6cfa73a2014-08-13 13:33:49 -07002665
dandovecfff212014-08-04 10:02:00 -07002666 LOOPER_END
2667}
2668
reeda8db7282015-07-07 10:22:31 -07002669void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002670#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002671 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002672#endif
reede3b38ce2016-01-08 09:18:44 -08002673 RETURN_ON_NULL(dr);
2674 if (x || y) {
2675 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2676 this->onDrawDrawable(dr, &matrix);
2677 } else {
2678 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002679 }
2680}
2681
reeda8db7282015-07-07 10:22:31 -07002682void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002683#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002684 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002685#endif
reede3b38ce2016-01-08 09:18:44 -08002686 RETURN_ON_NULL(dr);
2687 if (matrix && matrix->isIdentity()) {
2688 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002689 }
reede3b38ce2016-01-08 09:18:44 -08002690 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002691}
2692
2693void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002694 // drawable bounds are no longer reliable (e.g. android displaylist)
2695 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002696 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002697}
2698
reed71c3c762015-06-24 10:29:17 -07002699void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002700 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002701 const SkRect* cull, const SkPaint* paint) {
2702 if (cull && this->quickReject(*cull)) {
2703 return;
2704 }
2705
2706 SkPaint pnt;
2707 if (paint) {
2708 pnt = *paint;
2709 }
halcanary9d524f22016-03-29 09:03:52 -07002710
halcanary96fcdcc2015-08-27 07:41:13 -07002711 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002712 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002713 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002714 }
2715 LOOPER_END
2716}
2717
reedf70b5312016-03-04 16:36:20 -08002718void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2719 SkASSERT(key);
2720
2721 SkPaint paint;
2722 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2723 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002724 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002725 }
2726 LOOPER_END
2727}
2728
reed@android.com8a1c16f2008-12-17 15:59:43 +00002729//////////////////////////////////////////////////////////////////////////////
2730// These methods are NOT virtual, and therefore must call back into virtual
2731// methods, rather than actually drawing themselves.
2732//////////////////////////////////////////////////////////////////////////////
2733
reed374772b2016-10-05 17:33:02 -07002734void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002736 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002737 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002738 this->drawPaint(paint);
2739}
2740
2741void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002742 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002743 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2744}
2745
Mike Reed3661bc92017-02-22 13:21:42 -05002746void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002747 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748 pts[0].set(x0, y0);
2749 pts[1].set(x1, y1);
2750 this->drawPoints(kLines_PointMode, 2, pts, paint);
2751}
2752
Mike Reed3661bc92017-02-22 13:21:42 -05002753void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002754 if (radius < 0) {
2755 radius = 0;
2756 }
2757
2758 SkRect r;
2759 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002760 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002761}
2762
2763void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2764 const SkPaint& paint) {
2765 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002766 SkRRect rrect;
2767 rrect.setRectXY(r, rx, ry);
2768 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769 } else {
2770 this->drawRect(r, paint);
2771 }
2772}
2773
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2775 SkScalar sweepAngle, bool useCenter,
2776 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002777 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002778 if (oval.isEmpty() || !sweepAngle) {
2779 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780 }
bsalomon21af9ca2016-08-25 12:29:23 -07002781 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782}
2783
2784void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2785 const SkPath& path, SkScalar hOffset,
2786 SkScalar vOffset, const SkPaint& paint) {
2787 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002788
reed@android.com8a1c16f2008-12-17 15:59:43 +00002789 matrix.setTranslate(hOffset, vOffset);
2790 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2791}
2792
reed@android.comf76bacf2009-05-13 14:00:33 +00002793///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002794
Mike Klein88d90712018-01-27 17:30:04 +00002795/**
2796 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2797 * against the playback cost of recursing into the subpicture to get at its actual ops.
2798 *
2799 * For now we pick a conservatively small value, though measurement (and other heuristics like
2800 * the type of ops contained) may justify changing this value.
2801 */
2802#define kMaxPictureOpsToUnrollInsteadOfRef 1
2803
reedd5fa1a42014-08-09 11:08:05 -07002804void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002805 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002806 RETURN_ON_NULL(picture);
2807
reede3b38ce2016-01-08 09:18:44 -08002808 if (matrix && matrix->isIdentity()) {
2809 matrix = nullptr;
2810 }
Mike Klein88d90712018-01-27 17:30:04 +00002811 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2812 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2813 picture->playback(this);
2814 } else {
2815 this->onDrawPicture(picture, matrix, paint);
2816 }
reedd5fa1a42014-08-09 11:08:05 -07002817}
robertphillips9b14f262014-06-04 05:40:44 -07002818
reedd5fa1a42014-08-09 11:08:05 -07002819void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2820 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002821 if (!paint || paint->canComputeFastBounds()) {
2822 SkRect bounds = picture->cullRect();
2823 if (paint) {
2824 paint->computeFastBounds(bounds, &bounds);
2825 }
2826 if (matrix) {
2827 matrix->mapRect(&bounds);
2828 }
2829 if (this->quickReject(bounds)) {
2830 return;
2831 }
2832 }
2833
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002834 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002835 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002836}
2837
reed@android.com8a1c16f2008-12-17 15:59:43 +00002838///////////////////////////////////////////////////////////////////////////////
2839///////////////////////////////////////////////////////////////////////////////
2840
reed3aafe112016-08-18 12:45:34 -07002841SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002842 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002843
2844 SkASSERT(canvas);
2845
reed3aafe112016-08-18 12:45:34 -07002846 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847 fDone = !fImpl->next();
2848}
2849
2850SkCanvas::LayerIter::~LayerIter() {
2851 fImpl->~SkDrawIter();
2852}
2853
2854void SkCanvas::LayerIter::next() {
2855 fDone = !fImpl->next();
2856}
2857
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002858SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002859 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002860}
2861
2862const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002863 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002864}
2865
2866const SkPaint& SkCanvas::LayerIter::paint() const {
2867 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002868 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002869 paint = &fDefaultPaint;
2870 }
2871 return *paint;
2872}
2873
Mike Reeda1361362017-03-07 09:37:29 -05002874void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2875 return fImpl->fDevice->onAsRgnClip(rgn);
2876}
2877
reed@android.com8a1c16f2008-12-17 15:59:43 +00002878int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2879int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002880
2881///////////////////////////////////////////////////////////////////////////////
2882
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002883static bool supported_for_raster_canvas(const SkImageInfo& info) {
2884 switch (info.alphaType()) {
2885 case kPremul_SkAlphaType:
2886 case kOpaque_SkAlphaType:
2887 break;
2888 default:
2889 return false;
2890 }
2891
2892 switch (info.colorType()) {
2893 case kAlpha_8_SkColorType:
2894 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002895 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002896 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002897 break;
2898 default:
2899 return false;
2900 }
2901
2902 return true;
2903}
2904
Mike Reed5df49342016-11-12 08:06:55 -06002905std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002906 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002907 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002908 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002909 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002910
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002911 SkBitmap bitmap;
2912 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002913 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002914 }
Mike Reed12f77342017-11-08 11:19:52 -05002915
2916 return props ?
2917 skstd::make_unique<SkCanvas>(bitmap, *props) :
2918 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002919}
reedd5fa1a42014-08-09 11:08:05 -07002920
2921///////////////////////////////////////////////////////////////////////////////
2922
Florin Malitaee424ac2016-12-01 12:47:59 -05002923SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2924 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2925
Florin Malita439ace92016-12-02 12:05:41 -05002926SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2927 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2928
Florin Malitaee424ac2016-12-01 12:47:59 -05002929SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2930 (void)this->INHERITED::getSaveLayerStrategy(rec);
2931 return kNoLayer_SaveLayerStrategy;
2932}
2933
2934///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002935
reed73603f32016-09-20 08:42:38 -07002936static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2937static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2938static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2939static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2940static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2941static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002942
2943///////////////////////////////////////////////////////////////////////////////////////////////////
2944
2945SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2946 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002947 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002948 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2949 SkIPoint origin = dev->getOrigin();
2950 SkMatrix ctm = this->getTotalMatrix();
2951 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2952
2953 SkIRect clip = fMCRec->fRasterClip.getBounds();
2954 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002955 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002956 clip.setEmpty();
2957 }
2958
2959 fAllocator->updateHandle(handle, ctm, clip);
2960 return handle;
2961 }
2962 return nullptr;
2963}
2964
2965static bool install(SkBitmap* bm, const SkImageInfo& info,
2966 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002967 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002968}
2969
2970SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2971 SkBitmap* bm) {
2972 SkRasterHandleAllocator::Rec rec;
2973 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2974 return nullptr;
2975 }
2976 return rec.fHandle;
2977}
2978
2979std::unique_ptr<SkCanvas>
2980SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2981 const SkImageInfo& info, const Rec* rec) {
2982 if (!alloc || !supported_for_raster_canvas(info)) {
2983 return nullptr;
2984 }
2985
2986 SkBitmap bm;
2987 Handle hndl;
2988
2989 if (rec) {
2990 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2991 } else {
2992 hndl = alloc->allocBitmap(info, &bm);
2993 }
2994 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2995}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002996
2997///////////////////////////////////////////////////////////////////////////////////////////////////
2998
2999