blob: 59365f76b08408934389405feffe3ed9de1993fb [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) {
reed129ed1c2016-02-22 06:42:31 -08001040 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1041 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001042 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001043 const bool hasImageFilter = paint && paint->getImageFilter();
1044
reed129ed1c2016-02-22 06:42:31 -08001045 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1046 // force to L32
Mike Kleine083f7c2018-02-07 12:54:27 -05001047 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -08001048 } else {
1049 // keep the same characteristics as the prev
Mike Kleine083f7c2018-02-07 12:54:27 -05001050 return SkImageInfo::Make(w, h, prev.colorType(), kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001051 }
1052}
1053
reed4960eee2015-12-18 07:09:18 -08001054void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1055 const SkRect* bounds = rec.fBounds;
1056 const SkPaint* paint = rec.fPaint;
1057 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1058
reed8c30a812016-04-20 16:36:51 -07001059 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001060 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001061 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001062 SkMatrix remainder;
1063 SkSize scale;
1064 /*
1065 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1066 * but they do handle scaling. To accommodate this, we do the following:
1067 *
1068 * 1. Stash off the current CTM
1069 * 2. Decompose the CTM into SCALE and REMAINDER
1070 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1071 * contains the REMAINDER
1072 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1073 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1074 * of the original imagefilter, and draw that (via drawSprite)
1075 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1076 *
1077 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1078 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1079 */
reed96a04f32016-04-25 09:25:15 -07001080 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001081 stashedMatrix.decomposeScale(&scale, &remainder))
1082 {
1083 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1084 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1085 SkPaint* p = lazyP.set(*paint);
1086 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1087 SkFilterQuality::kLow_SkFilterQuality,
1088 sk_ref_sp(imageFilter)));
1089 imageFilter = p->getImageFilter();
1090 paint = p;
1091 }
reed8c30a812016-04-20 16:36:51 -07001092
junov@chromium.orga907ac32012-02-24 21:54:07 +00001093 // do this before we create the layer. We don't call the public save() since
1094 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001095 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001096
junov@chromium.orga907ac32012-02-24 21:54:07 +00001097 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001098 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001099 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100 }
1101
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001102 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1103 // the clipRectBounds() call above?
1104 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001105 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001106 }
1107
reed8dc0ccb2015-03-20 06:32:52 -07001108 SkPixelGeometry geo = fProps.pixelGeometry();
1109 if (paint) {
reed76033be2015-03-14 10:54:31 -07001110 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001111 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001112 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001113 }
1114 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001115
robertphillips5139e502016-07-19 05:10:40 -07001116 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001117 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001118 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001119 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001120 }
reedb2db8982014-11-13 12:41:02 -08001121
Mike Kleine083f7c2018-02-07 12:54:27 -05001122 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001123
Hal Canary704cd322016-11-07 14:13:52 -05001124 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001125 {
reed70ee31b2015-12-10 13:44:45 -08001126 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001127 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001128 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001129 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001130 preserveLCDText,
1131 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001132 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1133 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001134 return;
reed61f501f2015-04-29 08:34:00 -07001135 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001136 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001137 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001138
Mike Reedb43a3e02017-02-11 10:18:58 -05001139 // only have a "next" if this new layer doesn't affect the clip (rare)
1140 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141 fMCRec->fLayer = layer;
1142 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001143
Mike Reedc61abee2017-02-28 17:45:27 -05001144 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001145 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001146 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001147 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001148
Mike Reedc42a1cd2017-02-14 14:25:14 -05001149 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1150
1151 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1152 if (layer->fNext) {
1153 // need to punch a hole in the previous device, so we don't draw there, given that
1154 // the new top-layer will allow drawing to happen "below" it.
1155 SkRegion hole(ir);
1156 do {
1157 layer = layer->fNext;
1158 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1159 } while (layer->fNext);
1160 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001161}
1162
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001163int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001164 if (0xFF == alpha) {
1165 return this->saveLayer(bounds, nullptr);
1166 } else {
1167 SkPaint tmpPaint;
1168 tmpPaint.setAlpha(alpha);
1169 return this->saveLayer(bounds, &tmpPaint);
1170 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001171}
1172
reed@android.com8a1c16f2008-12-17 15:59:43 +00001173void SkCanvas::internalRestore() {
1174 SkASSERT(fMCStack.count() != 0);
1175
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001176 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001177 DeviceCM* layer = fMCRec->fLayer; // may be null
1178 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001179 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180
1181 // now do the normal restore()
1182 fMCRec->~MCRec(); // balanced in save()
1183 fMCStack.pop_back();
1184 fMCRec = (MCRec*)fMCStack.back();
1185
Mike Reedc42a1cd2017-02-14 14:25:14 -05001186 if (fMCRec) {
1187 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1188 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001189
reed@android.com8a1c16f2008-12-17 15:59:43 +00001190 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1191 since if we're being recorded, we don't want to record this (the
1192 recorder will have already recorded the restore).
1193 */
bsalomon49f085d2014-09-05 13:34:00 -07001194 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001195 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001196 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001197 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001198 layer->fPaint.get(),
1199 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001200 // restore what we smashed in internalSaveLayer
1201 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001202 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001203 delete layer;
reedb679ca82015-04-07 04:40:48 -07001204 } else {
1205 // we're at the root
reeda499f902015-05-01 09:34:31 -07001206 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001207 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001208 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001209 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001210 }
msarettfbfa2582016-08-12 08:29:08 -07001211
1212 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001213 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001214 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1215 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216}
1217
reede8f30622016-03-23 18:59:25 -07001218sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001219 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001220 props = &fProps;
1221 }
1222 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001223}
1224
reede8f30622016-03-23 18:59:25 -07001225sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001226 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001227 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001228}
1229
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001230SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001231 return this->onImageInfo();
1232}
1233
1234SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001235 SkBaseDevice* dev = this->getDevice();
1236 if (dev) {
1237 return dev->imageInfo();
1238 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001239 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001240 }
1241}
1242
brianosman898235c2016-04-06 07:38:23 -07001243bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001244 return this->onGetProps(props);
1245}
1246
1247bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001248 SkBaseDevice* dev = this->getDevice();
1249 if (dev) {
1250 if (props) {
1251 *props = fProps;
1252 }
1253 return true;
1254 } else {
1255 return false;
1256 }
1257}
1258
reed6ceeebd2016-03-09 14:26:26 -08001259bool SkCanvas::peekPixels(SkPixmap* pmap) {
1260 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001261}
1262
reed884e97c2015-05-26 11:31:54 -07001263bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001264 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001265 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001266}
1267
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001268void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001269 SkPixmap pmap;
1270 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001271 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001272 }
1273 if (info) {
1274 *info = pmap.info();
1275 }
1276 if (rowBytes) {
1277 *rowBytes = pmap.rowBytes();
1278 }
1279 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001280 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001281 }
reed884e97c2015-05-26 11:31:54 -07001282 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001283}
1284
reed884e97c2015-05-26 11:31:54 -07001285bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001286 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001287 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001288}
1289
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291
Florin Malita53f77bd2017-04-28 13:48:37 -04001292void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1293 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001295 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296 paint = &tmp;
1297 }
reed@google.com4b226022011-01-11 18:32:13 +00001298
reed@google.com8926b162012-03-23 15:36:36 +00001299 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001300
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001302 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001303 paint = &looper.paint();
1304 SkImageFilter* filter = paint->getImageFilter();
1305 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001306 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001307 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1308 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001309 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1310 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001311 }
reed@google.com76dd2772012-01-05 21:15:07 +00001312 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001313 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315 }
reeda2217ef2016-07-20 06:04:34 -07001316
reed@google.com4e2b3d32011-04-07 14:18:59 +00001317 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318}
1319
reed32704672015-12-16 08:27:10 -08001320/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001321
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001322void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001323 if (dx || dy) {
1324 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001325 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001326
reedfe69b502016-09-12 06:31:48 -07001327 // Translate shouldn't affect the is-scale-translateness of the matrix.
1328 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001329
Mike Reedc42a1cd2017-02-14 14:25:14 -05001330 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001331
reedfe69b502016-09-12 06:31:48 -07001332 this->didTranslate(dx,dy);
1333 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334}
1335
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001336void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001337 SkMatrix m;
1338 m.setScale(sx, sy);
1339 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340}
1341
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001342void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001343 SkMatrix m;
1344 m.setRotate(degrees);
1345 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346}
1347
bungeman7438bfc2016-07-12 15:01:19 -07001348void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1349 SkMatrix m;
1350 m.setRotate(degrees, px, py);
1351 this->concat(m);
1352}
1353
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001354void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001355 SkMatrix m;
1356 m.setSkew(sx, sy);
1357 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001358}
1359
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001360void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001361 if (matrix.isIdentity()) {
1362 return;
1363 }
1364
reed2ff1fce2014-12-11 07:07:37 -08001365 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001366 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001367 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001368
Mike Reed7627fa52017-02-08 10:07:53 -05001369 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001370
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001371 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001372}
1373
reed8c30a812016-04-20 16:36:51 -07001374void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001375 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001376 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001377
Mike Reedc42a1cd2017-02-14 14:25:14 -05001378 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001379}
1380
1381void SkCanvas::setMatrix(const SkMatrix& matrix) {
1382 this->checkForDeferredSave();
1383 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001384 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385}
1386
reed@android.com8a1c16f2008-12-17 15:59:43 +00001387void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001388 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389}
1390
1391//////////////////////////////////////////////////////////////////////////////
1392
Mike Reedc1f77742016-12-09 09:00:50 -05001393void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001394 if (!rect.isFinite()) {
1395 return;
1396 }
reed2ff1fce2014-12-11 07:07:37 -08001397 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001398 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1399 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001400}
1401
Mike Reedc1f77742016-12-09 09:00:50 -05001402void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001403 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001404
Mike Reed7627fa52017-02-08 10:07:53 -05001405 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001406
reedc64eff52015-11-21 12:39:45 -08001407 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001408 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1409 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001410 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001411}
1412
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001413void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1414 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001415 if (fClipRestrictionRect.isEmpty()) {
1416 // we notify the device, but we *dont* resolve deferred saves (since we're just
1417 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001418 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001419 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001420 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001421 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001422 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001423 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001424 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1425 }
1426}
1427
Mike Reedc1f77742016-12-09 09:00:50 -05001428void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001429 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001430 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001431 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001432 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1433 } else {
1434 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001435 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001436}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001437
Mike Reedc1f77742016-12-09 09:00:50 -05001438void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001439 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001440
Brian Salomona3b45d42016-10-03 11:36:16 -04001441 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001442
Mike Reed7627fa52017-02-08 10:07:53 -05001443 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001444
Mike Reed20800c82017-11-15 16:09:04 -05001445 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1446 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001447 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001448}
1449
Mike Reedc1f77742016-12-09 09:00:50 -05001450void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001451 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001452 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001453
1454 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1455 SkRect r;
1456 if (path.isRect(&r)) {
1457 this->onClipRect(r, op, edgeStyle);
1458 return;
1459 }
1460 SkRRect rrect;
1461 if (path.isOval(&r)) {
1462 rrect.setOval(r);
1463 this->onClipRRect(rrect, op, edgeStyle);
1464 return;
1465 }
1466 if (path.isRRect(&rrect)) {
1467 this->onClipRRect(rrect, op, edgeStyle);
1468 return;
1469 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001470 }
robertphillips39f05382015-11-24 09:30:12 -08001471
1472 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001473}
1474
Mike Reedc1f77742016-12-09 09:00:50 -05001475void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001476 AutoValidateClip avc(this);
1477
Brian Salomona3b45d42016-10-03 11:36:16 -04001478 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001479
Mike Reed7627fa52017-02-08 10:07:53 -05001480 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001481
Brian Salomona3b45d42016-10-03 11:36:16 -04001482 const SkPath* rasterClipPath = &path;
1483 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001484 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1485 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001486 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001487}
1488
Mike Reedc1f77742016-12-09 09:00:50 -05001489void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001490 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001491 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001492}
1493
Mike Reedc1f77742016-12-09 09:00:50 -05001494void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001495 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001496
reed@google.com5c3d1472011-02-22 19:12:23 +00001497 AutoValidateClip avc(this);
1498
Mike Reed20800c82017-11-15 16:09:04 -05001499 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001500 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501}
1502
reed@google.com819c9212011-02-23 18:56:55 +00001503#ifdef SK_DEBUG
1504void SkCanvas::validateClip() const {
1505 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001506 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001507 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001508 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001509 return;
1510 }
reed@google.com819c9212011-02-23 18:56:55 +00001511}
1512#endif
1513
Mike Reeda1361362017-03-07 09:37:29 -05001514bool SkCanvas::androidFramework_isClipAA() const {
1515 bool containsAA = false;
1516
1517 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1518
1519 return containsAA;
1520}
1521
1522class RgnAccumulator {
1523 SkRegion* fRgn;
1524public:
1525 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1526 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1527 SkIPoint origin = device->getOrigin();
1528 if (origin.x() | origin.y()) {
1529 rgn->translate(origin.x(), origin.y());
1530 }
1531 fRgn->op(*rgn, SkRegion::kUnion_Op);
1532 }
1533};
1534
1535void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1536 RgnAccumulator accum(rgn);
1537 SkRegion tmp;
1538
1539 rgn->setEmpty();
1540 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001541}
1542
reed@google.com5c3d1472011-02-22 19:12:23 +00001543///////////////////////////////////////////////////////////////////////////////
1544
reed@google.com754de5f2014-02-24 19:38:20 +00001545bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001546 return fMCRec->fRasterClip.isEmpty();
1547
1548 // TODO: should we only use the conservative answer in a recording canvas?
1549#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001550 SkBaseDevice* dev = this->getTopDevice();
1551 // if no device we return true
1552 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001553#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001554}
1555
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001556bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001557 SkBaseDevice* dev = this->getTopDevice();
1558 // if no device we return false
1559 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001560}
1561
msarettfbfa2582016-08-12 08:29:08 -07001562static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1563#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1564 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1565 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1566 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1567 return 0xF != _mm_movemask_ps(mask);
1568#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1569 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1570 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1571 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1572 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1573#else
1574 SkRect devRectAsRect;
1575 SkRect devClipAsRect;
1576 devRect.store(&devRectAsRect.fLeft);
1577 devClip.store(&devClipAsRect.fLeft);
1578 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1579#endif
1580}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001581
msarettfbfa2582016-08-12 08:29:08 -07001582// It's important for this function to not be inlined. Otherwise the compiler will share code
1583// between the fast path and the slow path, resulting in two slow paths.
1584static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1585 const SkMatrix& matrix) {
1586 SkRect deviceRect;
1587 matrix.mapRect(&deviceRect, src);
1588 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1589}
1590
1591bool SkCanvas::quickReject(const SkRect& src) const {
1592#ifdef SK_DEBUG
1593 // Verify that fDeviceClipBounds are set properly.
1594 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001595 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001596 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001597 } else {
msarettfbfa2582016-08-12 08:29:08 -07001598 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001599 }
msarettfbfa2582016-08-12 08:29:08 -07001600
msarett9637ea92016-08-18 14:03:30 -07001601 // Verify that fIsScaleTranslate is set properly.
1602 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001603#endif
1604
msarett9637ea92016-08-18 14:03:30 -07001605 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001606 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1607 }
1608
1609 // We inline the implementation of mapScaleTranslate() for the fast path.
1610 float sx = fMCRec->fMatrix.getScaleX();
1611 float sy = fMCRec->fMatrix.getScaleY();
1612 float tx = fMCRec->fMatrix.getTranslateX();
1613 float ty = fMCRec->fMatrix.getTranslateY();
1614 Sk4f scale(sx, sy, sx, sy);
1615 Sk4f trans(tx, ty, tx, ty);
1616
1617 // Apply matrix.
1618 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1619
1620 // Make sure left < right, top < bottom.
1621 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1622 Sk4f min = Sk4f::Min(ltrb, rblt);
1623 Sk4f max = Sk4f::Max(ltrb, rblt);
1624 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1625 // ARM this sequence generates the fastest (a single instruction).
1626 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1627
1628 // Check if the device rect is NaN or outside the clip.
1629 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001630}
1631
reed@google.com3b3e8952012-08-16 20:53:31 +00001632bool SkCanvas::quickReject(const SkPath& path) const {
1633 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001634}
1635
Mike Klein83c8dd92017-11-28 17:08:45 -05001636SkRect SkCanvas::getLocalClipBounds() const {
1637 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001638 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001639 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001640 }
1641
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001642 SkMatrix inverse;
1643 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001644 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001645 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001646 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001647
Mike Reed42e8c532017-01-23 14:09:13 -05001648 SkRect bounds;
1649 SkRect r;
1650 // adjust it outwards in case we are antialiasing
1651 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001652
Mike Reed42e8c532017-01-23 14:09:13 -05001653 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1654 ibounds.fRight + inset, ibounds.fBottom + inset);
1655 inverse.mapRect(&bounds, r);
1656 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657}
1658
Mike Klein83c8dd92017-11-28 17:08:45 -05001659SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001660 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001661}
1662
reed@android.com8a1c16f2008-12-17 15:59:43 +00001663const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001664 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001665}
1666
Brian Osman11052242016-10-27 14:47:55 -04001667GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001668 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001669 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001670}
1671
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001672GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001673 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001674 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001675}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001676
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001677void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1678 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001679 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001680 if (outer.isEmpty()) {
1681 return;
1682 }
1683 if (inner.isEmpty()) {
1684 this->drawRRect(outer, paint);
1685 return;
1686 }
1687
1688 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001689 // be able to return ...
1690 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001691 //
1692 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001693 if (!outer.getBounds().contains(inner.getBounds())) {
1694 return;
1695 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001696
1697 this->onDrawDRRect(outer, inner, paint);
1698}
1699
reed41af9662015-01-05 07:49:08 -08001700void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001701 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001702 this->onDrawPaint(paint);
1703}
1704
1705void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001706 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001707 // To avoid redundant logic in our culling code and various backends, we always sort rects
1708 // before passing them along.
1709 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001710}
1711
msarettdca352e2016-08-26 06:37:45 -07001712void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001713 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001714 if (region.isEmpty()) {
1715 return;
1716 }
1717
1718 if (region.isRect()) {
1719 return this->drawIRect(region.getBounds(), paint);
1720 }
1721
1722 this->onDrawRegion(region, paint);
1723}
1724
reed41af9662015-01-05 07:49:08 -08001725void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001726 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001727 // To avoid redundant logic in our culling code and various backends, we always sort rects
1728 // before passing them along.
1729 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001730}
1731
1732void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001733 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001734 this->onDrawRRect(rrect, paint);
1735}
1736
1737void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001738 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001739 this->onDrawPoints(mode, count, pts, paint);
1740}
1741
Mike Reede88a1cb2017-03-17 09:50:46 -04001742void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1743 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001744 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001745 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001746 this->onDrawVerticesObject(vertices.get(), mode, paint);
1747}
1748
1749void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001750 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001751 RETURN_ON_NULL(vertices);
1752 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001753}
1754
1755void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001756 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001757 this->onDrawPath(path, paint);
1758}
1759
reeda85d4d02015-05-06 12:56:48 -07001760void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001761 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001762 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001763 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001764}
1765
Mike Reedc4e31092018-01-30 11:15:27 -05001766// Returns true if the rect can be "filled" : non-empty and finite
1767static bool fillable(const SkRect& r) {
1768 SkScalar w = r.width();
1769 SkScalar h = r.height();
1770 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1771}
1772
reede47829b2015-08-06 10:02:53 -07001773void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1774 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001775 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001776 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001777 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001778 return;
1779 }
1780 this->onDrawImageRect(image, &src, dst, paint, constraint);
1781}
reed41af9662015-01-05 07:49:08 -08001782
reed84984ef2015-07-17 07:09:43 -07001783void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1784 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001785 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001786 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001787}
1788
reede47829b2015-08-06 10:02:53 -07001789void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1790 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001791 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001792 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1793 constraint);
1794}
reede47829b2015-08-06 10:02:53 -07001795
reed4c21dc52015-06-25 12:32:03 -07001796void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1797 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001798 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001799 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001800 if (dst.isEmpty()) {
1801 return;
1802 }
msarett552bca92016-08-03 06:53:26 -07001803 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1804 this->onDrawImageNine(image, center, dst, paint);
1805 } else {
reede47829b2015-08-06 10:02:53 -07001806 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001807 }
reed4c21dc52015-06-25 12:32:03 -07001808}
1809
msarett16882062016-08-16 09:31:08 -07001810void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1811 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001812 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001813 RETURN_ON_NULL(image);
1814 if (dst.isEmpty()) {
1815 return;
1816 }
msarett71df2d72016-09-30 12:41:42 -07001817
1818 SkIRect bounds;
1819 Lattice latticePlusBounds = lattice;
1820 if (!latticePlusBounds.fBounds) {
1821 bounds = SkIRect::MakeWH(image->width(), image->height());
1822 latticePlusBounds.fBounds = &bounds;
1823 }
1824
1825 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1826 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001827 } else {
1828 this->drawImageRect(image, dst, paint);
1829 }
1830}
1831
reed41af9662015-01-05 07:49:08 -08001832void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001833 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001834 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001835 return;
1836 }
reed41af9662015-01-05 07:49:08 -08001837 this->onDrawBitmap(bitmap, dx, dy, paint);
1838}
1839
reede47829b2015-08-06 10:02:53 -07001840void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001841 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001842 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001843 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001844 return;
1845 }
reede47829b2015-08-06 10:02:53 -07001846 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001847}
1848
reed84984ef2015-07-17 07:09:43 -07001849void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1850 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001851 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001852}
1853
reede47829b2015-08-06 10:02:53 -07001854void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1855 SrcRectConstraint constraint) {
1856 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1857 constraint);
1858}
reede47829b2015-08-06 10:02:53 -07001859
reed41af9662015-01-05 07:49:08 -08001860void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1861 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001862 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001863 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001864 return;
1865 }
msarett552bca92016-08-03 06:53:26 -07001866 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1867 this->onDrawBitmapNine(bitmap, center, dst, paint);
1868 } else {
reeda5517e22015-07-14 10:54:12 -07001869 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001870 }
reed41af9662015-01-05 07:49:08 -08001871}
1872
msarettc573a402016-08-02 08:05:56 -07001873void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1874 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001875 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001876 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001877 return;
1878 }
msarett71df2d72016-09-30 12:41:42 -07001879
1880 SkIRect bounds;
1881 Lattice latticePlusBounds = lattice;
1882 if (!latticePlusBounds.fBounds) {
1883 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1884 latticePlusBounds.fBounds = &bounds;
1885 }
1886
1887 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1888 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001889 } else {
msarett16882062016-08-16 09:31:08 -07001890 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001891 }
msarettc573a402016-08-02 08:05:56 -07001892}
1893
reed71c3c762015-06-24 10:29:17 -07001894void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001895 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001896 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001897 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001898 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001899 if (count <= 0) {
1900 return;
1901 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001902 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001903 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001904 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001905}
1906
reedf70b5312016-03-04 16:36:20 -08001907void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001908 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001909 if (key) {
1910 this->onDrawAnnotation(rect, key, value);
1911 }
1912}
1913
reede47829b2015-08-06 10:02:53 -07001914void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1915 const SkPaint* paint, SrcRectConstraint constraint) {
1916 if (src) {
1917 this->drawImageRect(image, *src, dst, paint, constraint);
1918 } else {
1919 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1920 dst, paint, constraint);
1921 }
1922}
1923void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1924 const SkPaint* paint, SrcRectConstraint constraint) {
1925 if (src) {
1926 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1927 } else {
1928 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1929 dst, paint, constraint);
1930 }
1931}
1932
Mike Reed4204da22017-05-17 08:53:36 -04001933void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001934 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001935 this->onDrawShadowRec(path, rec);
1936}
1937
1938void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1939 SkPaint paint;
1940 const SkRect& pathBounds = path.getBounds();
1941
1942 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1943 while (iter.next()) {
1944 iter.fDevice->drawShadow(path, rec);
1945 }
1946 LOOPER_END
1947}
1948
reed@android.com8a1c16f2008-12-17 15:59:43 +00001949//////////////////////////////////////////////////////////////////////////////
1950// These are the virtual drawing methods
1951//////////////////////////////////////////////////////////////////////////////
1952
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001953void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001954 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001955 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1956 }
1957}
1958
reed41af9662015-01-05 07:49:08 -08001959void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001960 this->internalDrawPaint(paint);
1961}
1962
1963void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001964 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001965
1966 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001967 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001968 }
1969
reed@google.com4e2b3d32011-04-07 14:18:59 +00001970 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001971}
1972
reed41af9662015-01-05 07:49:08 -08001973void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1974 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001975 if ((long)count <= 0) {
1976 return;
1977 }
1978
Mike Reed822128b2017-02-28 16:41:03 -05001979 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001980 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001981 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001982 // special-case 2 points (common for drawing a single line)
1983 if (2 == count) {
1984 r.set(pts[0], pts[1]);
1985 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001986 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001987 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001988 if (!r.isFinite()) {
1989 return;
1990 }
Mike Reed822128b2017-02-28 16:41:03 -05001991 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001992 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1993 return;
1994 }
1995 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001996 }
reed@google.coma584aed2012-05-16 14:06:02 +00001997
halcanary96fcdcc2015-08-27 07:41:13 -07001998 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002000 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002002 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002003 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004 }
reed@google.com4b226022011-01-11 18:32:13 +00002005
reed@google.com4e2b3d32011-04-07 14:18:59 +00002006 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002007}
2008
reed4a167172016-08-18 17:15:25 -07002009static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2010 return ((intptr_t)paint.getImageFilter() |
2011#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2012 (intptr_t)canvas->getDrawFilter() |
2013#endif
2014 (intptr_t)paint.getLooper() ) != 0;
2015}
2016
reed41af9662015-01-05 07:49:08 -08002017void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002018 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002019 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002020 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002021 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002022 return;
2023 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002024 }
reed@google.com4b226022011-01-11 18:32:13 +00002025
reed4a167172016-08-18 17:15:25 -07002026 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002027 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002028
reed4a167172016-08-18 17:15:25 -07002029 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002030 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002031 }
2032
2033 LOOPER_END
2034 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002035 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002036 SkDrawIter iter(this);
2037 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002038 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002039 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002040 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002041}
2042
msarett44df6512016-08-25 13:54:30 -07002043void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002044 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002045 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002046 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002047 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2048 return;
2049 }
msarett44df6512016-08-25 13:54:30 -07002050 }
2051
Mike Reed822128b2017-02-28 16:41:03 -05002052 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002053
2054 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002055 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002056 }
2057
2058 LOOPER_END
2059}
2060
reed41af9662015-01-05 07:49:08 -08002061void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002062 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002063 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002064 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002065 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002066 return;
2067 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002068 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002069
Mike Reed822128b2017-02-28 16:41:03 -05002070 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002071
2072 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002073 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002074 }
2075
2076 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002077}
2078
bsalomonac3aa242016-08-19 11:25:19 -07002079void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2080 SkScalar sweepAngle, bool useCenter,
2081 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002082 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002083 if (paint.canComputeFastBounds()) {
2084 SkRect storage;
2085 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002086 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002087 return;
2088 }
bsalomonac3aa242016-08-19 11:25:19 -07002089 }
2090
Mike Reed822128b2017-02-28 16:41:03 -05002091 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002092
2093 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002094 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002095 }
2096
2097 LOOPER_END
2098}
2099
reed41af9662015-01-05 07:49:08 -08002100void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002101 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002102 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002103 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2104 return;
2105 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002106 }
2107
2108 if (rrect.isRect()) {
2109 // call the non-virtual version
2110 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002111 return;
2112 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002113 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002114 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2115 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002116 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002117
Mike Reed822128b2017-02-28 16:41:03 -05002118 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002119
2120 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002121 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002122 }
2123
2124 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002125}
2126
Mike Reed822128b2017-02-28 16:41:03 -05002127void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002128 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002129 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002130 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2131 return;
2132 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002133 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002134
Mike Reed822128b2017-02-28 16:41:03 -05002135 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002136
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002137 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002138 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002139 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002140
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002141 LOOPER_END
2142}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002143
reed41af9662015-01-05 07:49:08 -08002144void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002145 if (!path.isFinite()) {
2146 return;
2147 }
2148
Mike Reed822128b2017-02-28 16:41:03 -05002149 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002150 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002151 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002152 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2153 return;
2154 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002155 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002156
Mike Reed822128b2017-02-28 16:41:03 -05002157 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002158 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002159 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002160 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002161 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002162 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002163
Mike Reed822128b2017-02-28 16:41:03 -05002164 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002165
2166 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002167 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002168 }
2169
reed@google.com4e2b3d32011-04-07 14:18:59 +00002170 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002171}
2172
reed262a71b2015-12-05 13:07:27 -08002173bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002174 if (!paint.getImageFilter()) {
2175 return false;
2176 }
2177
2178 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002179 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002180 return false;
2181 }
2182
2183 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2184 // Once we can filter and the filter will return a result larger than itself, we should be
2185 // able to remove this constraint.
2186 // skbug.com/4526
2187 //
2188 SkPoint pt;
2189 ctm.mapXY(x, y, &pt);
2190 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2191 return ir.contains(fMCRec->fRasterClip.getBounds());
2192}
2193
reeda85d4d02015-05-06 12:56:48 -07002194void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07002195 SkRect bounds = SkRect::MakeXYWH(x, y,
2196 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002197 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002198 SkRect tmp = bounds;
2199 if (paint) {
2200 paint->computeFastBounds(tmp, &tmp);
2201 }
2202 if (this->quickReject(tmp)) {
2203 return;
2204 }
reeda85d4d02015-05-06 12:56:48 -07002205 }
halcanary9d524f22016-03-29 09:03:52 -07002206
reeda85d4d02015-05-06 12:56:48 -07002207 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002208 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002209 paint = lazy.init();
2210 }
reed262a71b2015-12-05 13:07:27 -08002211
reeda2217ef2016-07-20 06:04:34 -07002212 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002213 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2214 *paint);
2215 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002216 special = this->getDevice()->makeSpecial(image);
2217 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002218 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002219 }
2220 }
2221
reed262a71b2015-12-05 13:07:27 -08002222 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2223
reeda85d4d02015-05-06 12:56:48 -07002224 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002225 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002226 if (special) {
2227 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002228 iter.fDevice->ctm().mapXY(x, y, &pt);
2229 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002230 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002231 SkScalarRoundToInt(pt.fY), pnt,
2232 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002233 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002234 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002235 }
reeda85d4d02015-05-06 12:56:48 -07002236 }
halcanary9d524f22016-03-29 09:03:52 -07002237
reeda85d4d02015-05-06 12:56:48 -07002238 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002239}
2240
reed41af9662015-01-05 07:49:08 -08002241void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002242 const SkPaint* paint, SrcRectConstraint constraint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002243 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002244 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002245 if (paint) {
2246 paint->computeFastBounds(dst, &storage);
2247 }
2248 if (this->quickReject(storage)) {
2249 return;
2250 }
reeda85d4d02015-05-06 12:56:48 -07002251 }
2252 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002253 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002254 paint = lazy.init();
2255 }
halcanary9d524f22016-03-29 09:03:52 -07002256
senorblancoc41e7e12015-12-07 12:51:30 -08002257 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002258 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002259
reeda85d4d02015-05-06 12:56:48 -07002260 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002261 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002262 }
halcanary9d524f22016-03-29 09:03:52 -07002263
reeda85d4d02015-05-06 12:56:48 -07002264 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002265}
2266
reed41af9662015-01-05 07:49:08 -08002267void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002268 SkDEBUGCODE(bitmap.validate();)
2269
reed33366972015-10-08 09:22:02 -07002270 if (bitmap.drawsNothing()) {
2271 return;
2272 }
2273
2274 SkLazyPaint lazy;
2275 if (nullptr == paint) {
2276 paint = lazy.init();
2277 }
2278
Mike Reed822128b2017-02-28 16:41:03 -05002279 SkRect bounds;
2280 bitmap.getBounds(&bounds);
2281 bounds.offset(x, y);
2282 bool canFastBounds = paint->canComputeFastBounds();
2283 if (canFastBounds) {
2284 SkRect storage;
2285 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002286 return;
2287 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002288 }
reed@google.com4b226022011-01-11 18:32:13 +00002289
reeda2217ef2016-07-20 06:04:34 -07002290 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002291 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2292 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002293 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002294 special = this->getDevice()->makeSpecial(bitmap);
2295 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002296 drawAsSprite = false;
2297 }
2298 }
2299
Mike Reed822128b2017-02-28 16:41:03 -05002300 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002301
2302 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002303 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002304 if (special) {
reed262a71b2015-12-05 13:07:27 -08002305 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002306 iter.fDevice->ctm().mapXY(x, y, &pt);
2307 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002308 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002309 SkScalarRoundToInt(pt.fY), pnt,
2310 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002311 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002312 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002313 }
reed33366972015-10-08 09:22:02 -07002314 }
msarettfbfa2582016-08-12 08:29:08 -07002315
reed33366972015-10-08 09:22:02 -07002316 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002317}
2318
reed@google.com9987ec32011-09-07 11:57:52 +00002319// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002320void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002321 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002322 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002323 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 return;
2325 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002326
halcanary96fcdcc2015-08-27 07:41:13 -07002327 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002328 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002329 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2330 return;
2331 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002332 }
reed@google.com3d608122011-11-21 15:16:16 +00002333
reed@google.com33535f32012-09-25 15:37:50 +00002334 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002335 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002336 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002337 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002338
senorblancoc41e7e12015-12-07 12:51:30 -08002339 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002340 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002341
reed@google.com33535f32012-09-25 15:37:50 +00002342 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002343 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002344 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002345
reed@google.com33535f32012-09-25 15:37:50 +00002346 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002347}
2348
reed41af9662015-01-05 07:49:08 -08002349void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002350 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002351 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002352 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002353}
2354
reed4c21dc52015-06-25 12:32:03 -07002355void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2356 const SkPaint* paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002357 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002358 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002359 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2360 return;
2361 }
reed@google.com3d608122011-11-21 15:16:16 +00002362 }
halcanary9d524f22016-03-29 09:03:52 -07002363
reed4c21dc52015-06-25 12:32:03 -07002364 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002365 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002366 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002367 }
halcanary9d524f22016-03-29 09:03:52 -07002368
senorblancoc41e7e12015-12-07 12:51:30 -08002369 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002370
reed4c21dc52015-06-25 12:32:03 -07002371 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002372 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002373 }
halcanary9d524f22016-03-29 09:03:52 -07002374
reed4c21dc52015-06-25 12:32:03 -07002375 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002376}
2377
reed41af9662015-01-05 07:49:08 -08002378void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2379 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002380 SkDEBUGCODE(bitmap.validate();)
2381
halcanary96fcdcc2015-08-27 07:41:13 -07002382 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002383 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002384 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2385 return;
2386 }
reed4c21dc52015-06-25 12:32:03 -07002387 }
halcanary9d524f22016-03-29 09:03:52 -07002388
reed4c21dc52015-06-25 12:32:03 -07002389 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002390 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002391 paint = lazy.init();
2392 }
halcanary9d524f22016-03-29 09:03:52 -07002393
senorblancoc41e7e12015-12-07 12:51:30 -08002394 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002395
reed4c21dc52015-06-25 12:32:03 -07002396 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002397 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002398 }
halcanary9d524f22016-03-29 09:03:52 -07002399
reed4c21dc52015-06-25 12:32:03 -07002400 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002401}
2402
msarett16882062016-08-16 09:31:08 -07002403void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2404 const SkPaint* paint) {
2405 if (nullptr == paint || paint->canComputeFastBounds()) {
2406 SkRect storage;
2407 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2408 return;
2409 }
2410 }
2411
2412 SkLazyPaint lazy;
2413 if (nullptr == paint) {
2414 paint = lazy.init();
2415 }
2416
2417 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2418
2419 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002420 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002421 }
2422
2423 LOOPER_END
2424}
2425
2426void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2427 const SkRect& dst, const SkPaint* paint) {
2428 if (nullptr == paint || paint->canComputeFastBounds()) {
2429 SkRect storage;
2430 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2431 return;
2432 }
2433 }
2434
2435 SkLazyPaint lazy;
2436 if (nullptr == paint) {
2437 paint = lazy.init();
2438 }
2439
2440 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2441
2442 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002443 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002444 }
2445
2446 LOOPER_END
2447}
2448
reed@google.comf67e4cf2011-03-15 20:56:58 +00002449class SkDeviceFilteredPaint {
2450public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002451 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002452 uint32_t filteredFlags = device->filterTextFlags(paint);
2453 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002454 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002455 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002456 fPaint = newPaint;
2457 } else {
2458 fPaint = &paint;
2459 }
2460 }
2461
reed@google.comf67e4cf2011-03-15 20:56:58 +00002462 const SkPaint& paint() const { return *fPaint; }
2463
2464private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002465 const SkPaint* fPaint;
2466 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002467};
2468
reed@google.come0d9ce82014-04-23 04:00:17 +00002469void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2470 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002471 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002472
2473 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002474 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002475 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476 }
2477
reed@google.com4e2b3d32011-04-07 14:18:59 +00002478 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002479}
2480
reed@google.come0d9ce82014-04-23 04:00:17 +00002481void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2482 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002483 SkPoint textOffset = SkPoint::Make(0, 0);
2484
halcanary96fcdcc2015-08-27 07:41:13 -07002485 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002486
reed@android.com8a1c16f2008-12-17 15:59:43 +00002487 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002488 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002489 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002490 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002491 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002492
reed@google.com4e2b3d32011-04-07 14:18:59 +00002493 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002494}
2495
reed@google.come0d9ce82014-04-23 04:00:17 +00002496void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2497 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002498
2499 SkPoint textOffset = SkPoint::Make(0, constY);
2500
halcanary96fcdcc2015-08-27 07:41:13 -07002501 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002502
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002504 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002505 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002506 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002507 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002508
reed@google.com4e2b3d32011-04-07 14:18:59 +00002509 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002510}
2511
reed@google.come0d9ce82014-04-23 04:00:17 +00002512void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2513 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002514 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002515
reed@android.com8a1c16f2008-12-17 15:59:43 +00002516 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002517 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002518 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002519 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002520
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002521 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002522}
2523
reed45561a02016-07-07 12:47:17 -07002524void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2525 const SkRect* cullRect, const SkPaint& paint) {
2526 if (cullRect && this->quickReject(*cullRect)) {
2527 return;
2528 }
2529
2530 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2531
2532 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002533 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002534 }
2535
2536 LOOPER_END
2537}
2538
fmalita00d5c2c2014-08-21 08:53:26 -07002539void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2540 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002541
fmalita85d5eb92015-03-04 11:20:12 -08002542 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002543 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002544 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002545 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002546 SkRect tmp;
2547 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2548 return;
2549 }
2550 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002551 }
2552
fmalita024f9962015-03-03 19:08:17 -08002553 // We cannot filter in the looper as we normally do, because the paint is
2554 // incomplete at this point (text-related attributes are embedded within blob run paints).
2555 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002556 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002557
fmalita85d5eb92015-03-04 11:20:12 -08002558 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002559
fmalitaaa1b9122014-08-28 14:32:24 -07002560 while (iter.next()) {
2561 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002562 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002563 }
2564
fmalitaaa1b9122014-08-28 14:32:24 -07002565 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002566
2567 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002568}
2569
Cary Clark2a475ea2017-04-28 15:35:12 -04002570void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2571 this->drawText(string.c_str(), string.size(), x, y, paint);
2572}
2573
reed@google.come0d9ce82014-04-23 04:00:17 +00002574// These will become non-virtual, so they always call the (virtual) onDraw... method
2575void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2576 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002577 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002578 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002579 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002580 this->onDrawText(text, byteLength, x, y, paint);
2581 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002582}
2583void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2584 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002585 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002586 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002587 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002588 this->onDrawPosText(text, byteLength, pos, paint);
2589 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002590}
2591void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2592 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002593 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002594 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002595 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002596 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2597 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002598}
2599void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2600 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002601 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002602 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002603 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002604 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2605 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002606}
reed45561a02016-07-07 12:47:17 -07002607void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2608 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002609 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002610 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002611 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002612 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2613 }
2614}
fmalita00d5c2c2014-08-21 08:53:26 -07002615void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2616 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002617 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002618 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002619 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002620 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002621}
reed@google.come0d9ce82014-04-23 04:00:17 +00002622
Mike Reede88a1cb2017-03-17 09:50:46 -04002623void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2624 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002625 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2626
2627 while (iter.next()) {
2628 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002629 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002630 }
2631
2632 LOOPER_END
2633}
2634
dandovb3c9d1c2014-08-12 08:34:29 -07002635void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002636 const SkPoint texCoords[4], SkBlendMode bmode,
2637 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002638 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002639 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002640 return;
2641 }
mtklein6cfa73a2014-08-13 13:33:49 -07002642
Mike Reedfaba3712016-11-03 14:45:31 -04002643 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002644}
2645
2646void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002647 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002648 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002649 // Since a patch is always within the convex hull of the control points, we discard it when its
2650 // bounding rectangle is completely outside the current clip.
2651 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002652 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002653 if (this->quickReject(bounds)) {
2654 return;
2655 }
mtklein6cfa73a2014-08-13 13:33:49 -07002656
Mike Reed435071e2017-05-23 11:22:56 -04002657 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2658
halcanary96fcdcc2015-08-27 07:41:13 -07002659 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002660
dandovecfff212014-08-04 10:02:00 -07002661 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002662 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002663 }
mtklein6cfa73a2014-08-13 13:33:49 -07002664
dandovecfff212014-08-04 10:02:00 -07002665 LOOPER_END
2666}
2667
reeda8db7282015-07-07 10:22:31 -07002668void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002669#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002670 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002671#endif
reede3b38ce2016-01-08 09:18:44 -08002672 RETURN_ON_NULL(dr);
2673 if (x || y) {
2674 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2675 this->onDrawDrawable(dr, &matrix);
2676 } else {
2677 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002678 }
2679}
2680
reeda8db7282015-07-07 10:22:31 -07002681void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002682#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002683 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002684#endif
reede3b38ce2016-01-08 09:18:44 -08002685 RETURN_ON_NULL(dr);
2686 if (matrix && matrix->isIdentity()) {
2687 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002688 }
reede3b38ce2016-01-08 09:18:44 -08002689 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002690}
2691
2692void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002693 // drawable bounds are no longer reliable (e.g. android displaylist)
2694 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002695 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002696}
2697
reed71c3c762015-06-24 10:29:17 -07002698void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002699 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002700 const SkRect* cull, const SkPaint* paint) {
2701 if (cull && this->quickReject(*cull)) {
2702 return;
2703 }
2704
2705 SkPaint pnt;
2706 if (paint) {
2707 pnt = *paint;
2708 }
halcanary9d524f22016-03-29 09:03:52 -07002709
halcanary96fcdcc2015-08-27 07:41:13 -07002710 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002711 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002712 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002713 }
2714 LOOPER_END
2715}
2716
reedf70b5312016-03-04 16:36:20 -08002717void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2718 SkASSERT(key);
2719
2720 SkPaint paint;
2721 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2722 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002723 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002724 }
2725 LOOPER_END
2726}
2727
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728//////////////////////////////////////////////////////////////////////////////
2729// These methods are NOT virtual, and therefore must call back into virtual
2730// methods, rather than actually drawing themselves.
2731//////////////////////////////////////////////////////////////////////////////
2732
reed374772b2016-10-05 17:33:02 -07002733void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002734 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002736 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002737 this->drawPaint(paint);
2738}
2739
2740void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002741 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2743}
2744
Mike Reed3661bc92017-02-22 13:21:42 -05002745void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002746 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002747 pts[0].set(x0, y0);
2748 pts[1].set(x1, y1);
2749 this->drawPoints(kLines_PointMode, 2, pts, paint);
2750}
2751
Mike Reed3661bc92017-02-22 13:21:42 -05002752void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753 if (radius < 0) {
2754 radius = 0;
2755 }
2756
2757 SkRect r;
2758 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002759 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002760}
2761
2762void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2763 const SkPaint& paint) {
2764 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002765 SkRRect rrect;
2766 rrect.setRectXY(r, rx, ry);
2767 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002768 } else {
2769 this->drawRect(r, paint);
2770 }
2771}
2772
reed@android.com8a1c16f2008-12-17 15:59:43 +00002773void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2774 SkScalar sweepAngle, bool useCenter,
2775 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002776 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002777 if (oval.isEmpty() || !sweepAngle) {
2778 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779 }
bsalomon21af9ca2016-08-25 12:29:23 -07002780 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781}
2782
2783void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2784 const SkPath& path, SkScalar hOffset,
2785 SkScalar vOffset, const SkPaint& paint) {
2786 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002787
reed@android.com8a1c16f2008-12-17 15:59:43 +00002788 matrix.setTranslate(hOffset, vOffset);
2789 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2790}
2791
reed@android.comf76bacf2009-05-13 14:00:33 +00002792///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002793
Mike Klein88d90712018-01-27 17:30:04 +00002794/**
2795 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2796 * against the playback cost of recursing into the subpicture to get at its actual ops.
2797 *
2798 * For now we pick a conservatively small value, though measurement (and other heuristics like
2799 * the type of ops contained) may justify changing this value.
2800 */
2801#define kMaxPictureOpsToUnrollInsteadOfRef 1
2802
reedd5fa1a42014-08-09 11:08:05 -07002803void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002804 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002805 RETURN_ON_NULL(picture);
2806
reede3b38ce2016-01-08 09:18:44 -08002807 if (matrix && matrix->isIdentity()) {
2808 matrix = nullptr;
2809 }
Mike Klein88d90712018-01-27 17:30:04 +00002810 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2811 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2812 picture->playback(this);
2813 } else {
2814 this->onDrawPicture(picture, matrix, paint);
2815 }
reedd5fa1a42014-08-09 11:08:05 -07002816}
robertphillips9b14f262014-06-04 05:40:44 -07002817
reedd5fa1a42014-08-09 11:08:05 -07002818void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2819 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002820 if (!paint || paint->canComputeFastBounds()) {
2821 SkRect bounds = picture->cullRect();
2822 if (paint) {
2823 paint->computeFastBounds(bounds, &bounds);
2824 }
2825 if (matrix) {
2826 matrix->mapRect(&bounds);
2827 }
2828 if (this->quickReject(bounds)) {
2829 return;
2830 }
2831 }
2832
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002833 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002834 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002835}
2836
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837///////////////////////////////////////////////////////////////////////////////
2838///////////////////////////////////////////////////////////////////////////////
2839
reed3aafe112016-08-18 12:45:34 -07002840SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002841 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842
2843 SkASSERT(canvas);
2844
reed3aafe112016-08-18 12:45:34 -07002845 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002846 fDone = !fImpl->next();
2847}
2848
2849SkCanvas::LayerIter::~LayerIter() {
2850 fImpl->~SkDrawIter();
2851}
2852
2853void SkCanvas::LayerIter::next() {
2854 fDone = !fImpl->next();
2855}
2856
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002857SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002858 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002859}
2860
2861const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002862 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002863}
2864
2865const SkPaint& SkCanvas::LayerIter::paint() const {
2866 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002867 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002868 paint = &fDefaultPaint;
2869 }
2870 return *paint;
2871}
2872
Mike Reeda1361362017-03-07 09:37:29 -05002873void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2874 return fImpl->fDevice->onAsRgnClip(rgn);
2875}
2876
reed@android.com8a1c16f2008-12-17 15:59:43 +00002877int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2878int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002879
2880///////////////////////////////////////////////////////////////////////////////
2881
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002882static bool supported_for_raster_canvas(const SkImageInfo& info) {
2883 switch (info.alphaType()) {
2884 case kPremul_SkAlphaType:
2885 case kOpaque_SkAlphaType:
2886 break;
2887 default:
2888 return false;
2889 }
2890
2891 switch (info.colorType()) {
2892 case kAlpha_8_SkColorType:
2893 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002894 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002895 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002896 break;
2897 default:
2898 return false;
2899 }
2900
2901 return true;
2902}
2903
Mike Reed5df49342016-11-12 08:06:55 -06002904std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002905 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002906 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002907 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002908 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002909
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002910 SkBitmap bitmap;
2911 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002912 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002913 }
Mike Reed12f77342017-11-08 11:19:52 -05002914
2915 return props ?
2916 skstd::make_unique<SkCanvas>(bitmap, *props) :
2917 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002918}
reedd5fa1a42014-08-09 11:08:05 -07002919
2920///////////////////////////////////////////////////////////////////////////////
2921
Florin Malitaee424ac2016-12-01 12:47:59 -05002922SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2923 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2924
Florin Malita439ace92016-12-02 12:05:41 -05002925SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2926 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2927
Florin Malitaee424ac2016-12-01 12:47:59 -05002928SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2929 (void)this->INHERITED::getSaveLayerStrategy(rec);
2930 return kNoLayer_SaveLayerStrategy;
2931}
2932
2933///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002934
reed73603f32016-09-20 08:42:38 -07002935static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2936static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2937static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2938static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2939static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2940static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002941
2942///////////////////////////////////////////////////////////////////////////////////////////////////
2943
2944SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2945 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002946 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002947 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2948 SkIPoint origin = dev->getOrigin();
2949 SkMatrix ctm = this->getTotalMatrix();
2950 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2951
2952 SkIRect clip = fMCRec->fRasterClip.getBounds();
2953 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002954 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002955 clip.setEmpty();
2956 }
2957
2958 fAllocator->updateHandle(handle, ctm, clip);
2959 return handle;
2960 }
2961 return nullptr;
2962}
2963
2964static bool install(SkBitmap* bm, const SkImageInfo& info,
2965 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002966 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002967}
2968
2969SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2970 SkBitmap* bm) {
2971 SkRasterHandleAllocator::Rec rec;
2972 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2973 return nullptr;
2974 }
2975 return rec.fHandle;
2976}
2977
2978std::unique_ptr<SkCanvas>
2979SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2980 const SkImageInfo& info, const Rec* rec) {
2981 if (!alloc || !supported_for_raster_canvas(info)) {
2982 return nullptr;
2983 }
2984
2985 SkBitmap bm;
2986 Handle hndl;
2987
2988 if (rec) {
2989 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2990 } else {
2991 hndl = alloc->allocBitmap(info, &bm);
2992 }
2993 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2994}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002995
2996///////////////////////////////////////////////////////////////////////////////////////////////////
2997
2998