blob: 94bc2a711c71f0bf6ab1e0ad72c50fa38c9a5539 [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
reed@google.comda17f752012-08-16 18:27:05 +0000172// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173//#define SK_TRACE_SAVERESTORE
174
175#ifdef SK_TRACE_SAVERESTORE
176 static int gLayerCounter;
177 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
178 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
179
180 static int gRecCounter;
181 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
182 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
183
184 static int gCanvasCounter;
185 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
186 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
187#else
188 #define inc_layer()
189 #define dec_layer()
190 #define inc_rec()
191 #define dec_rec()
192 #define inc_canvas()
193 #define dec_canvas()
194#endif
195
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000196typedef SkTLazy<SkPaint> SkLazyPaint;
197
reedc83a2972015-07-16 07:40:45 -0700198void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000199 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700200 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
201 ? SkSurface::kDiscard_ContentChangeMode
202 : SkSurface::kRetain_ContentChangeMode);
203 }
204}
205
206void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
207 ShaderOverrideOpacity overrideOpacity) {
208 if (fSurfaceBase) {
209 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
210 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
211 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
212 // and therefore we don't care which mode we're in.
213 //
214 if (fSurfaceBase->outstandingImageSnapshot()) {
215 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
216 mode = SkSurface::kDiscard_ContentChangeMode;
217 }
218 }
219 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000220 }
221}
222
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000225/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 The clip/matrix/proc are fields that reflect the top of the save/restore
227 stack. Whenever the canvas changes, it marks a dirty flag, and then before
228 these are used (assuming we're not on a layer) we rebuild these cache
229 values: they reflect the top of the save stack, but translated and clipped
230 by the device's XY offset and bitmap-bounds.
231*/
232struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400233 DeviceCM* fNext;
234 sk_sp<SkBaseDevice> fDevice;
235 SkRasterClip fClip;
236 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
237 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400238 sk_sp<SkImage> fClipImage;
239 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240
Florin Malita53f77bd2017-04-28 13:48:37 -0400241 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000242 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700243 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400244 , fDevice(std::move(device))
245 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700246 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000247 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400248 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400249 {}
reed@google.com4b226022011-01-11 18:32:13 +0000250
mtkleinfeaadee2015-04-08 11:25:48 -0700251 void reset(const SkIRect& bounds) {
252 SkASSERT(!fPaint);
253 SkASSERT(!fNext);
254 SkASSERT(fDevice);
255 fClip.setRect(bounds);
256 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257};
258
259/* This is the record we keep for each save/restore level in the stack.
260 Since a level optionally copies the matrix and/or stack, we have pointers
261 for these fields. If the value is copied for this level, the copy is
262 stored in the ...Storage field, and the pointer points to that. If the
263 value is not copied for this level, we ignore ...Storage, and just point
264 at the corresponding value in the previous level in the stack.
265*/
266class SkCanvas::MCRec {
267public:
reed1f836ee2014-07-07 07:49:34 -0700268 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700269 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270 /* If there are any layers in the stack, this points to the top-most
271 one that is at or below this level in the stack (so we know what
272 bitmap/device to draw into from this level. This value is NOT
273 reference counted, since the real owner is either our fLayer field,
274 or a previous one in a lower level.)
275 */
Mike Reeda1361362017-03-07 09:37:29 -0500276 DeviceCM* fTopLayer;
277 SkConservativeClip fRasterClip;
278 SkMatrix fMatrix;
279 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280
Mike Reeda1361362017-03-07 09:37:29 -0500281 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700282 fFilter = nullptr;
283 fLayer = nullptr;
284 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800285 fMatrix.reset();
286 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700287
reedd9544982014-09-09 18:46:22 -0700288 // don't bother initializing fNext
289 inc_rec();
290 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400291 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700292 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700293 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700294 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800295 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700296
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 // don't bother initializing fNext
298 inc_rec();
299 }
300 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000301 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700302 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303 dec_rec();
304 }
mtkleinfeaadee2015-04-08 11:25:48 -0700305
306 void reset(const SkIRect& bounds) {
307 SkASSERT(fLayer);
308 SkASSERT(fDeferredSaveCount == 0);
309
310 fMatrix.reset();
311 fRasterClip.setRect(bounds);
312 fLayer->reset(bounds);
313 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314};
315
Mike Reeda1361362017-03-07 09:37:29 -0500316class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317public:
Mike Reeda1361362017-03-07 09:37:29 -0500318 SkDrawIter(SkCanvas* canvas)
319 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
320 {}
reed@google.com4b226022011-01-11 18:32:13 +0000321
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000323 const DeviceCM* rec = fCurrLayer;
324 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400325 fDevice = rec->fDevice.get();
326 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700328 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 return true;
330 }
331 return false;
332 }
reed@google.com4b226022011-01-11 18:32:13 +0000333
reed@google.com6f8f2922011-03-04 22:27:10 +0000334 int getX() const { return fDevice->getOrigin().x(); }
335 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000337
Mike Reed99330ba2017-02-22 11:01:08 -0500338 SkBaseDevice* fDevice;
339
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 const DeviceCM* fCurrLayer;
342 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343};
344
Florin Malita713b8ef2017-04-28 10:57:24 -0400345#define FOR_EACH_TOP_DEVICE( code ) \
346 do { \
347 DeviceCM* layer = fMCRec->fTopLayer; \
348 while (layer) { \
349 SkBaseDevice* device = layer->fDevice.get(); \
350 if (device) { \
351 code; \
352 } \
353 layer = layer->fNext; \
354 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500355 } while (0)
356
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357/////////////////////////////////////////////////////////////////////////////
358
reeddbc3cef2015-04-29 12:18:57 -0700359static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
360 return lazy->isValid() ? lazy->get() : lazy->set(orig);
361}
362
363/**
364 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700365 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700366 */
reedd053ce92016-03-22 10:17:23 -0700367static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700368 SkImageFilter* imgf = paint.getImageFilter();
369 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700370 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700371 }
372
reedd053ce92016-03-22 10:17:23 -0700373 SkColorFilter* imgCFPtr;
374 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700375 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700376 }
reedd053ce92016-03-22 10:17:23 -0700377 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700378
379 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700380 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700381 // there is no existing paint colorfilter, so we can just return the imagefilter's
382 return imgCF;
383 }
384
385 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
386 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500387 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700388}
389
senorblanco87e066e2015-10-28 11:23:36 -0700390/**
391 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
392 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
393 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
394 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
395 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
396 * conservative "effective" bounds based on the settings in the paint... with one exception. This
397 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
398 * deliberately ignored.
399 */
400static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
401 const SkRect& rawBounds,
402 SkRect* storage) {
403 SkPaint tmpUnfiltered(paint);
404 tmpUnfiltered.setImageFilter(nullptr);
405 if (tmpUnfiltered.canComputeFastBounds()) {
406 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
407 } else {
408 return rawBounds;
409 }
410}
411
reed@android.com8a1c16f2008-12-17 15:59:43 +0000412class AutoDrawLooper {
413public:
senorblanco87e066e2015-10-28 11:23:36 -0700414 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
415 // paint. It's used to determine the size of the offscreen layer for filters.
416 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700417 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700418 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000419 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800420#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800422#else
423 fFilter = nullptr;
424#endif
reed4a8126e2014-09-22 07:29:03 -0700425 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000426 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700427 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000428 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429
reedd053ce92016-03-22 10:17:23 -0700430 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700431 if (simplifiedCF) {
432 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700433 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700434 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700435 fPaint = paint;
436 }
437
438 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700439 /**
440 * We implement ImageFilters for a given draw by creating a layer, then applying the
441 * imagefilter to the pixels of that layer (its backing surface/image), and then
442 * we call restore() to xfer that layer to the main canvas.
443 *
444 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
445 * 2. Generate the src pixels:
446 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
447 * return (fPaint). We then draw the primitive (using srcover) into a cleared
448 * buffer/surface.
449 * 3. Restore the layer created in #1
450 * The imagefilter is passed the buffer/surface from the layer (now filled with the
451 * src pixels of the primitive). It returns a new "filtered" buffer, which we
452 * draw onto the previous layer using the xfermode from the original paint.
453 */
reed@google.com8926b162012-03-23 15:36:36 +0000454 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500455 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700456 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700457 SkRect storage;
458 if (rawBounds) {
459 // Make rawBounds include all paint outsets except for those due to image filters.
460 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
461 }
reedbfd5f172016-01-07 11:28:08 -0800462 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700463 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700464 fTempLayerForImageFilter = true;
465 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000466 }
467
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000468 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500469 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000470 fIsSimple = false;
471 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700472 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000473 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700474 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000475 }
476 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000477
reed@android.com8a1c16f2008-12-17 15:59:43 +0000478 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700479 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000480 fCanvas->internalRestore();
481 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000483 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000484
reed@google.com4e2b3d32011-04-07 14:18:59 +0000485 const SkPaint& paint() const {
486 SkASSERT(fPaint);
487 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000488 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000489
reed@google.com129ec222012-05-15 13:24:09 +0000490 bool next(SkDrawFilter::Type drawType) {
491 if (fDone) {
492 return false;
493 } else if (fIsSimple) {
494 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000495 return !fPaint->nothingToDraw();
496 } else {
497 return this->doNext(drawType);
498 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000499 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000500
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500502 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700503 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000504 SkCanvas* fCanvas;
505 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000506 SkDrawFilter* fFilter;
507 const SkPaint* fPaint;
508 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700509 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000510 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000511 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000512 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400513 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000514
515 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516};
517
reed@google.com129ec222012-05-15 13:24:09 +0000518bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700519 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000520 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700521 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000522
reeddbc3cef2015-04-29 12:18:57 -0700523 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
524 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000525
reed5c476fb2015-04-20 08:04:21 -0700526 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700527 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700528 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000529 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000530
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000531 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000532 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000533 return false;
534 }
535 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000536 if (!fFilter->filter(paint, drawType)) {
537 fDone = true;
538 return false;
539 }
halcanary96fcdcc2015-08-27 07:41:13 -0700540 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000541 // no looper means we only draw once
542 fDone = true;
543 }
544 }
545 fPaint = paint;
546
547 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000548 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000549 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000550 }
551
552 // call this after any possible paint modifiers
553 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700554 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000555 return false;
556 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000557 return true;
558}
559
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560////////// macros to place around the internal draw calls //////////////////
561
reed3aafe112016-08-18 12:45:34 -0700562#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
563 this->predrawNotify(); \
564 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
565 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800566 SkDrawIter iter(this);
567
568
reed@google.com8926b162012-03-23 15:36:36 +0000569#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000570 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700571 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000572 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000573 SkDrawIter iter(this);
574
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000575#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000576 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700577 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000578 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000580
reedc83a2972015-07-16 07:40:45 -0700581#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
582 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700583 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700584 while (looper.next(type)) { \
585 SkDrawIter iter(this);
586
reed@google.com4e2b3d32011-04-07 14:18:59 +0000587#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588
589////////////////////////////////////////////////////////////////////////////
590
msarettfbfa2582016-08-12 08:29:08 -0700591static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
592 if (bounds.isEmpty()) {
593 return SkRect::MakeEmpty();
594 }
595
596 // Expand bounds out by 1 in case we are anti-aliasing. We store the
597 // bounds as floats to enable a faster quick reject implementation.
598 SkRect dst;
599 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
600 return dst;
601}
602
mtkleinfeaadee2015-04-08 11:25:48 -0700603void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
604 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700605 fMCRec->reset(bounds);
606
607 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500608 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400609 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700610 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700611 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700612}
613
reedd9544982014-09-09 18:46:22 -0700614SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800615 if (device && device->forceConservativeRasterClip()) {
616 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
617 }
reed42b73eb2015-11-20 13:42:42 -0800618
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000619 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800620 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700621 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622
623 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500624 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500625 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700626 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000627
reeda499f902015-05-01 09:34:31 -0700628 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
629 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400630 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700631
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633
halcanary96fcdcc2015-08-27 07:41:13 -0700634 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000635
reedf92c8662014-08-18 08:02:43 -0700636 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700637 // The root device and the canvas should always have the same pixel geometry
638 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800639 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700640 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500641
Mike Reedc42a1cd2017-02-14 14:25:14 -0500642 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700643 }
msarettfbfa2582016-08-12 08:29:08 -0700644
reedf92c8662014-08-18 08:02:43 -0700645 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646}
647
reed@google.comcde92112011-07-06 20:00:52 +0000648SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000649 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700650 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000651{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000652 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000653
halcanary96fcdcc2015-08-27 07:41:13 -0700654 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000655}
656
reed96a857e2015-01-25 10:33:58 -0800657SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000658 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800659 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000660{
661 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700662
Mike Reed566e53c2017-03-10 10:49:45 -0500663 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700664 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700665}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000666
reed78e27682014-11-19 08:04:34 -0800667SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700668 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700669 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700670{
671 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700672
Mike Reed566e53c2017-03-10 10:49:45 -0500673 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
674 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700675}
676
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000677SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000678 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700679 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000680{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700682
reedd9544982014-09-09 18:46:22 -0700683 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684}
685
robertphillipsfcf78292015-06-19 11:49:52 -0700686SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
687 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700688 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700689{
690 inc_canvas();
691
692 this->init(device, flags);
693}
694
reed4a8126e2014-09-22 07:29:03 -0700695SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700696 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700697 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700698{
699 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700700
Hal Canary704cd322016-11-07 14:13:52 -0500701 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
702 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700703}
reed29c857d2014-09-21 10:25:07 -0700704
Mike Reed356f7c22017-01-10 11:58:39 -0500705SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
706 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700707 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
708 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500709 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700710{
711 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700712
Mike Reed356f7c22017-01-10 11:58:39 -0500713 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500714 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715}
716
Mike Reed356f7c22017-01-10 11:58:39 -0500717SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
718
Matt Sarett31f99ce2017-04-11 08:46:01 -0400719#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
720SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
721 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
722 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
723 , fAllocator(nullptr)
724{
725 inc_canvas();
726
727 SkBitmap tmp(bitmap);
728 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
729 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
730 this->init(device.get(), kDefault_InitFlags);
731}
732#endif
733
reed@android.com8a1c16f2008-12-17 15:59:43 +0000734SkCanvas::~SkCanvas() {
735 // free up the contents of our deque
736 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000737
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 this->internalRestore(); // restore the last, since we're going away
739
halcanary385fe4d2015-08-26 13:07:48 -0700740 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000741
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742 dec_canvas();
743}
744
fmalita53d9f1c2016-01-25 06:23:54 -0800745#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746SkDrawFilter* SkCanvas::getDrawFilter() const {
747 return fMCRec->fFilter;
748}
749
750SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700751 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
753 return filter;
754}
fmalita77650002016-01-21 18:47:11 -0800755#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000756
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000757SkMetaData& SkCanvas::getMetaData() {
758 // metadata users are rare, so we lazily allocate it. If that changes we
759 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700760 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000761 fMetaData = new SkMetaData;
762 }
763 return *fMetaData;
764}
765
reed@android.com8a1c16f2008-12-17 15:59:43 +0000766///////////////////////////////////////////////////////////////////////////////
767
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000768void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700769 this->onFlush();
770}
771
772void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000773 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000774 if (device) {
775 device->flush();
776 }
777}
778
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000779SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000780 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000781 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
782}
783
senorblancoafc7cce2016-02-02 18:44:15 -0800784SkIRect SkCanvas::getTopLayerBounds() const {
785 SkBaseDevice* d = this->getTopDevice();
786 if (!d) {
787 return SkIRect::MakeEmpty();
788 }
789 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
790}
791
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000792SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000793 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000794 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000795 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400796 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797}
798
Florin Malita0ed3b642017-01-13 16:56:38 +0000799SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400800 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000801}
802
Mike Reed353196f2017-07-21 11:01:18 -0400803bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000804 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400805 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000806}
807
Mike Reed353196f2017-07-21 11:01:18 -0400808bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
809 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400810}
811
812bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
813 SkPixmap pm;
814 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
815}
816
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000817bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400818 SkPixmap pm;
819 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700820 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000821 }
822 return false;
823}
824
Matt Sarett03dd6d52017-01-23 12:15:09 -0500825bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000826 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000827 SkBaseDevice* device = this->getDevice();
828 if (!device) {
829 return false;
830 }
831
Matt Sarett03dd6d52017-01-23 12:15:09 -0500832 // This check gives us an early out and prevents generation ID churn on the surface.
833 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
834 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
835 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
836 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000837 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000838
Matt Sarett03dd6d52017-01-23 12:15:09 -0500839 // Tell our owning surface to bump its generation ID.
840 const bool completeOverwrite =
841 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700842 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700843
Matt Sarett03dd6d52017-01-23 12:15:09 -0500844 // This can still fail, most notably in the case of a invalid color type or alpha type
845 // conversion. We could pull those checks into this function and avoid the unnecessary
846 // generation ID bump. But then we would be performing those checks twice, since they
847 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400848 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000849}
reed@google.com51df9e32010-12-23 19:29:18 +0000850
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851//////////////////////////////////////////////////////////////////////////////
852
reed2ff1fce2014-12-11 07:07:37 -0800853void SkCanvas::checkForDeferredSave() {
854 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800855 this->doSave();
856 }
857}
858
reedf0090cb2014-11-26 08:55:51 -0800859int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800860#ifdef SK_DEBUG
861 int count = 0;
862 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
863 for (;;) {
864 const MCRec* rec = (const MCRec*)iter.next();
865 if (!rec) {
866 break;
867 }
868 count += 1 + rec->fDeferredSaveCount;
869 }
870 SkASSERT(count == fSaveCount);
871#endif
872 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800873}
874
875int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800876 fSaveCount += 1;
877 fMCRec->fDeferredSaveCount += 1;
878 return this->getSaveCount() - 1; // return our prev value
879}
880
881void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800882 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700883
884 SkASSERT(fMCRec->fDeferredSaveCount > 0);
885 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800886 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800887}
888
889void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800890 if (fMCRec->fDeferredSaveCount > 0) {
891 SkASSERT(fSaveCount > 1);
892 fSaveCount -= 1;
893 fMCRec->fDeferredSaveCount -= 1;
894 } else {
895 // check for underflow
896 if (fMCStack.count() > 1) {
897 this->willRestore();
898 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700899 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800900 this->internalRestore();
901 this->didRestore();
902 }
reedf0090cb2014-11-26 08:55:51 -0800903 }
904}
905
906void SkCanvas::restoreToCount(int count) {
907 // sanity check
908 if (count < 1) {
909 count = 1;
910 }
mtkleinf0f14112014-12-12 08:46:25 -0800911
reedf0090cb2014-11-26 08:55:51 -0800912 int n = this->getSaveCount() - count;
913 for (int i = 0; i < n; ++i) {
914 this->restore();
915 }
916}
917
reed2ff1fce2014-12-11 07:07:37 -0800918void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700920 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000921 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000922
Mike Reedc42a1cd2017-02-14 14:25:14 -0500923 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000924}
925
reed4960eee2015-12-18 07:09:18 -0800926bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800927 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000928}
929
reed4960eee2015-12-18 07:09:18 -0800930bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700931 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500932 SkIRect clipBounds = this->getDeviceClipBounds();
933 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000934 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000935 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000936
reed96e657d2015-03-10 17:30:07 -0700937 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
938
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000939 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700940 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800941 if (bounds && !imageFilter->canComputeFastBounds()) {
942 bounds = nullptr;
943 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000944 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000945 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700946 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000947 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700948 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949 r.roundOut(&ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950 } else { // no user bounds, so just use the clip
951 ir = clipBounds;
952 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800953
954 // early exit if the layer's bounds are clipped out
955 if (!ir.intersect(clipBounds)) {
956 if (BoundsAffectsClip(saveLayerFlags)) {
957 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
958 fMCRec->fRasterClip.setEmpty();
959 fDeviceClipBounds.setEmpty();
960 }
961 return false;
962 }
reed180aec42015-03-11 10:39:04 -0700963 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964
reed4960eee2015-12-18 07:09:18 -0800965 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700966 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700967 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700968 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000969 }
970
971 if (intersection) {
972 *intersection = ir;
973 }
974 return true;
975}
976
reed4960eee2015-12-18 07:09:18 -0800977
reed4960eee2015-12-18 07:09:18 -0800978int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
979 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000980}
981
reed70ee31b2015-12-10 13:44:45 -0800982int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800983 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
984}
985
Cary Clarke041e312018-03-06 13:00:52 -0500986int SkCanvas::saveLayer(const SaveLayerRec& rec) {
987 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
reed4960eee2015-12-18 07:09:18 -0800988 fSaveCount += 1;
Cary Clarke041e312018-03-06 13:00:52 -0500989 this->internalSaveLayer(rec, strategy);
reed4960eee2015-12-18 07:09:18 -0800990 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800991}
992
reeda2217ef2016-07-20 06:04:34 -0700993void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500994 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500995 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700996 SkDraw draw;
997 SkRasterClip rc;
998 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
999 if (!dst->accessPixels(&draw.fDst)) {
1000 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001001 }
reeda2217ef2016-07-20 06:04:34 -07001002 draw.fMatrix = &SkMatrix::I();
1003 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001004
1005 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001006 if (filter) {
1007 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1008 }
reeda2217ef2016-07-20 06:04:34 -07001009
Mike Reedc42a1cd2017-02-14 14:25:14 -05001010 int x = src->getOrigin().x() - dstOrigin.x();
1011 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001012 auto special = src->snapSpecial();
1013 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001014 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -07001015 }
robertphillips7354a4b2015-12-16 05:08:27 -08001016}
reed70ee31b2015-12-10 13:44:45 -08001017
Mike Kleine083f7c2018-02-07 12:54:27 -05001018static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -05001019 // Need to force L32 for now if we have an image filter.
1020 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
1021 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -05001022 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -08001023 }
Mike Klein649fb732018-02-26 15:09:16 -05001024
1025 SkColorType ct = prev.colorType();
1026 if (prev.bytesPerPixel() <= 4) {
1027 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
1028 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
1029 ct = kN32_SkColorType;
1030 }
1031 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001032}
1033
reed4960eee2015-12-18 07:09:18 -08001034void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1035 const SkRect* bounds = rec.fBounds;
1036 const SkPaint* paint = rec.fPaint;
1037 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1038
reed8c30a812016-04-20 16:36:51 -07001039 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001040 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001041 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001042 SkMatrix remainder;
1043 SkSize scale;
1044 /*
1045 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1046 * but they do handle scaling. To accommodate this, we do the following:
1047 *
1048 * 1. Stash off the current CTM
1049 * 2. Decompose the CTM into SCALE and REMAINDER
1050 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1051 * contains the REMAINDER
1052 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1053 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1054 * of the original imagefilter, and draw that (via drawSprite)
1055 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1056 *
1057 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1058 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1059 */
reed96a04f32016-04-25 09:25:15 -07001060 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001061 stashedMatrix.decomposeScale(&scale, &remainder))
1062 {
1063 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1064 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1065 SkPaint* p = lazyP.set(*paint);
1066 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1067 SkFilterQuality::kLow_SkFilterQuality,
1068 sk_ref_sp(imageFilter)));
1069 imageFilter = p->getImageFilter();
1070 paint = p;
1071 }
reed8c30a812016-04-20 16:36:51 -07001072
junov@chromium.orga907ac32012-02-24 21:54:07 +00001073 // do this before we create the layer. We don't call the public save() since
1074 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001075 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001076
junov@chromium.orga907ac32012-02-24 21:54:07 +00001077 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001078 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001079 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001080 }
1081
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001082 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1083 // the clipRectBounds() call above?
1084 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001085 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001086 }
1087
reed8dc0ccb2015-03-20 06:32:52 -07001088 SkPixelGeometry geo = fProps.pixelGeometry();
1089 if (paint) {
reed76033be2015-03-14 10:54:31 -07001090 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001091 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001092 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001093 }
1094 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095
robertphillips5139e502016-07-19 05:10:40 -07001096 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001097 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001098 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001099 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001100 }
reedb2db8982014-11-13 12:41:02 -08001101
Mike Kleine083f7c2018-02-07 12:54:27 -05001102 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001103
Hal Canary704cd322016-11-07 14:13:52 -05001104 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001105 {
reed70ee31b2015-12-10 13:44:45 -08001106 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001107 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001108 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001109 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001110 preserveLCDText,
1111 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001112 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1113 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001114 return;
reed61f501f2015-04-29 08:34:00 -07001115 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001116 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001117 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001118
Mike Reedb43a3e02017-02-11 10:18:58 -05001119 // only have a "next" if this new layer doesn't affect the clip (rare)
1120 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001121 fMCRec->fLayer = layer;
1122 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001123
Mike Reedc61abee2017-02-28 17:45:27 -05001124 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001125 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001126 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001127 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001128
Mike Reedc42a1cd2017-02-14 14:25:14 -05001129 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1130
1131 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1132 if (layer->fNext) {
1133 // need to punch a hole in the previous device, so we don't draw there, given that
1134 // the new top-layer will allow drawing to happen "below" it.
1135 SkRegion hole(ir);
1136 do {
1137 layer = layer->fNext;
1138 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1139 } while (layer->fNext);
1140 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141}
1142
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001143int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001144 if (0xFF == alpha) {
1145 return this->saveLayer(bounds, nullptr);
1146 } else {
1147 SkPaint tmpPaint;
1148 tmpPaint.setAlpha(alpha);
1149 return this->saveLayer(bounds, &tmpPaint);
1150 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001151}
1152
reed@android.com8a1c16f2008-12-17 15:59:43 +00001153void SkCanvas::internalRestore() {
1154 SkASSERT(fMCStack.count() != 0);
1155
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001156 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157 DeviceCM* layer = fMCRec->fLayer; // may be null
1158 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001159 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001160
1161 // now do the normal restore()
1162 fMCRec->~MCRec(); // balanced in save()
1163 fMCStack.pop_back();
1164 fMCRec = (MCRec*)fMCStack.back();
1165
Mike Reedc42a1cd2017-02-14 14:25:14 -05001166 if (fMCRec) {
1167 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1168 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001169
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1171 since if we're being recorded, we don't want to record this (the
1172 recorder will have already recorded the restore).
1173 */
bsalomon49f085d2014-09-05 13:34:00 -07001174 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001175 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001176 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001177 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001178 layer->fPaint.get(),
1179 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001180 // restore what we smashed in internalSaveLayer
1181 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001182 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001183 delete layer;
reedb679ca82015-04-07 04:40:48 -07001184 } else {
1185 // we're at the root
reeda499f902015-05-01 09:34:31 -07001186 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001187 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001188 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001190 }
msarettfbfa2582016-08-12 08:29:08 -07001191
1192 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001193 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001194 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1195 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196}
1197
reede8f30622016-03-23 18:59:25 -07001198sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001199 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001200 props = &fProps;
1201 }
1202 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001203}
1204
reede8f30622016-03-23 18:59:25 -07001205sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001206 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001207 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001208}
1209
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001210SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001211 return this->onImageInfo();
1212}
1213
1214SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001215 SkBaseDevice* dev = this->getDevice();
1216 if (dev) {
1217 return dev->imageInfo();
1218 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001219 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001220 }
1221}
1222
brianosman898235c2016-04-06 07:38:23 -07001223bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001224 return this->onGetProps(props);
1225}
1226
1227bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001228 SkBaseDevice* dev = this->getDevice();
1229 if (dev) {
1230 if (props) {
1231 *props = fProps;
1232 }
1233 return true;
1234 } else {
1235 return false;
1236 }
1237}
1238
reed6ceeebd2016-03-09 14:26:26 -08001239bool SkCanvas::peekPixels(SkPixmap* pmap) {
1240 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001241}
1242
reed884e97c2015-05-26 11:31:54 -07001243bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001244 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001245 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001246}
1247
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001248void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001249 SkPixmap pmap;
1250 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001251 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001252 }
1253 if (info) {
1254 *info = pmap.info();
1255 }
1256 if (rowBytes) {
1257 *rowBytes = pmap.rowBytes();
1258 }
1259 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001260 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001261 }
reed884e97c2015-05-26 11:31:54 -07001262 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001263}
1264
reed884e97c2015-05-26 11:31:54 -07001265bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001266 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001267 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001268}
1269
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271
Florin Malita53f77bd2017-04-28 13:48:37 -04001272void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1273 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001275 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276 paint = &tmp;
1277 }
reed@google.com4b226022011-01-11 18:32:13 +00001278
reed@google.com8926b162012-03-23 15:36:36 +00001279 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001280
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001282 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001283 paint = &looper.paint();
1284 SkImageFilter* filter = paint->getImageFilter();
1285 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001286 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001287 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1288 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001289 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1290 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001291 }
reed@google.com76dd2772012-01-05 21:15:07 +00001292 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001293 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001294 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 }
reeda2217ef2016-07-20 06:04:34 -07001296
reed@google.com4e2b3d32011-04-07 14:18:59 +00001297 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298}
1299
reed32704672015-12-16 08:27:10 -08001300/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001301
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001302void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001303 if (dx || dy) {
1304 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001305 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001306
reedfe69b502016-09-12 06:31:48 -07001307 // Translate shouldn't affect the is-scale-translateness of the matrix.
1308 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001309
Mike Reedc42a1cd2017-02-14 14:25:14 -05001310 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001311
reedfe69b502016-09-12 06:31:48 -07001312 this->didTranslate(dx,dy);
1313 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314}
1315
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001316void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001317 SkMatrix m;
1318 m.setScale(sx, sy);
1319 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320}
1321
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001322void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001323 SkMatrix m;
1324 m.setRotate(degrees);
1325 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326}
1327
bungeman7438bfc2016-07-12 15:01:19 -07001328void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1329 SkMatrix m;
1330 m.setRotate(degrees, px, py);
1331 this->concat(m);
1332}
1333
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001334void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001335 SkMatrix m;
1336 m.setSkew(sx, sy);
1337 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001338}
1339
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001340void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001341 if (matrix.isIdentity()) {
1342 return;
1343 }
1344
reed2ff1fce2014-12-11 07:07:37 -08001345 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001346 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001347 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001348
Mike Reed7627fa52017-02-08 10:07:53 -05001349 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001350
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001351 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001352}
1353
reed8c30a812016-04-20 16:36:51 -07001354void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001355 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001356 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001357
Mike Reedc42a1cd2017-02-14 14:25:14 -05001358 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001359}
1360
1361void SkCanvas::setMatrix(const SkMatrix& matrix) {
1362 this->checkForDeferredSave();
1363 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001364 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001365}
1366
reed@android.com8a1c16f2008-12-17 15:59:43 +00001367void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001368 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001369}
1370
1371//////////////////////////////////////////////////////////////////////////////
1372
Mike Reedc1f77742016-12-09 09:00:50 -05001373void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001374 if (!rect.isFinite()) {
1375 return;
1376 }
reed2ff1fce2014-12-11 07:07:37 -08001377 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001378 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1379 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001380}
1381
Mike Reedc1f77742016-12-09 09:00:50 -05001382void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001383 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001384
Mike Reed7627fa52017-02-08 10:07:53 -05001385 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001386
reedc64eff52015-11-21 12:39:45 -08001387 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001388 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1389 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001390 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001391}
1392
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001393void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1394 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001395 if (fClipRestrictionRect.isEmpty()) {
1396 // we notify the device, but we *dont* resolve deferred saves (since we're just
1397 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001398 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001399 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001400 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001401 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001402 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001403 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001404 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1405 }
1406}
1407
Mike Reedc1f77742016-12-09 09:00:50 -05001408void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001409 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001410 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001411 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001412 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1413 } else {
1414 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001415 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001416}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001417
Mike Reedc1f77742016-12-09 09:00:50 -05001418void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001419 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001420
Brian Salomona3b45d42016-10-03 11:36:16 -04001421 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001422
Mike Reed7627fa52017-02-08 10:07:53 -05001423 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001424
Mike Reed20800c82017-11-15 16:09:04 -05001425 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1426 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001427 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001428}
1429
Mike Reedc1f77742016-12-09 09:00:50 -05001430void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001431 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001432 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001433
1434 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1435 SkRect r;
1436 if (path.isRect(&r)) {
1437 this->onClipRect(r, op, edgeStyle);
1438 return;
1439 }
1440 SkRRect rrect;
1441 if (path.isOval(&r)) {
1442 rrect.setOval(r);
1443 this->onClipRRect(rrect, op, edgeStyle);
1444 return;
1445 }
1446 if (path.isRRect(&rrect)) {
1447 this->onClipRRect(rrect, op, edgeStyle);
1448 return;
1449 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001450 }
robertphillips39f05382015-11-24 09:30:12 -08001451
1452 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001453}
1454
Mike Reedc1f77742016-12-09 09:00:50 -05001455void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001456 AutoValidateClip avc(this);
1457
Brian Salomona3b45d42016-10-03 11:36:16 -04001458 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001459
Mike Reed7627fa52017-02-08 10:07:53 -05001460 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001461
Brian Salomona3b45d42016-10-03 11:36:16 -04001462 const SkPath* rasterClipPath = &path;
1463 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001464 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1465 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001466 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001467}
1468
Mike Reedc1f77742016-12-09 09:00:50 -05001469void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001470 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001471 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001472}
1473
Mike Reedc1f77742016-12-09 09:00:50 -05001474void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001475 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001476
reed@google.com5c3d1472011-02-22 19:12:23 +00001477 AutoValidateClip avc(this);
1478
Mike Reed20800c82017-11-15 16:09:04 -05001479 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001480 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001481}
1482
reed@google.com819c9212011-02-23 18:56:55 +00001483#ifdef SK_DEBUG
1484void SkCanvas::validateClip() const {
1485 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001486 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001487 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001488 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001489 return;
1490 }
reed@google.com819c9212011-02-23 18:56:55 +00001491}
1492#endif
1493
Mike Reeda1361362017-03-07 09:37:29 -05001494bool SkCanvas::androidFramework_isClipAA() const {
1495 bool containsAA = false;
1496
1497 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1498
1499 return containsAA;
1500}
1501
1502class RgnAccumulator {
1503 SkRegion* fRgn;
1504public:
1505 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1506 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1507 SkIPoint origin = device->getOrigin();
1508 if (origin.x() | origin.y()) {
1509 rgn->translate(origin.x(), origin.y());
1510 }
1511 fRgn->op(*rgn, SkRegion::kUnion_Op);
1512 }
1513};
1514
1515void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1516 RgnAccumulator accum(rgn);
1517 SkRegion tmp;
1518
1519 rgn->setEmpty();
1520 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001521}
1522
reed@google.com5c3d1472011-02-22 19:12:23 +00001523///////////////////////////////////////////////////////////////////////////////
1524
reed@google.com754de5f2014-02-24 19:38:20 +00001525bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001526 return fMCRec->fRasterClip.isEmpty();
1527
1528 // TODO: should we only use the conservative answer in a recording canvas?
1529#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001530 SkBaseDevice* dev = this->getTopDevice();
1531 // if no device we return true
1532 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001533#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001534}
1535
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001536bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001537 SkBaseDevice* dev = this->getTopDevice();
1538 // if no device we return false
1539 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001540}
1541
msarettfbfa2582016-08-12 08:29:08 -07001542static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1543#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1544 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1545 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1546 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1547 return 0xF != _mm_movemask_ps(mask);
1548#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1549 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1550 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1551 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1552 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1553#else
1554 SkRect devRectAsRect;
1555 SkRect devClipAsRect;
1556 devRect.store(&devRectAsRect.fLeft);
1557 devClip.store(&devClipAsRect.fLeft);
1558 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1559#endif
1560}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001561
msarettfbfa2582016-08-12 08:29:08 -07001562// It's important for this function to not be inlined. Otherwise the compiler will share code
1563// between the fast path and the slow path, resulting in two slow paths.
1564static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1565 const SkMatrix& matrix) {
1566 SkRect deviceRect;
1567 matrix.mapRect(&deviceRect, src);
1568 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1569}
1570
1571bool SkCanvas::quickReject(const SkRect& src) const {
1572#ifdef SK_DEBUG
1573 // Verify that fDeviceClipBounds are set properly.
1574 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001575 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001576 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001577 } else {
msarettfbfa2582016-08-12 08:29:08 -07001578 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001579 }
msarettfbfa2582016-08-12 08:29:08 -07001580
msarett9637ea92016-08-18 14:03:30 -07001581 // Verify that fIsScaleTranslate is set properly.
1582 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001583#endif
1584
msarett9637ea92016-08-18 14:03:30 -07001585 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001586 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1587 }
1588
1589 // We inline the implementation of mapScaleTranslate() for the fast path.
1590 float sx = fMCRec->fMatrix.getScaleX();
1591 float sy = fMCRec->fMatrix.getScaleY();
1592 float tx = fMCRec->fMatrix.getTranslateX();
1593 float ty = fMCRec->fMatrix.getTranslateY();
1594 Sk4f scale(sx, sy, sx, sy);
1595 Sk4f trans(tx, ty, tx, ty);
1596
1597 // Apply matrix.
1598 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1599
1600 // Make sure left < right, top < bottom.
1601 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1602 Sk4f min = Sk4f::Min(ltrb, rblt);
1603 Sk4f max = Sk4f::Max(ltrb, rblt);
1604 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1605 // ARM this sequence generates the fastest (a single instruction).
1606 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1607
1608 // Check if the device rect is NaN or outside the clip.
1609 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001610}
1611
reed@google.com3b3e8952012-08-16 20:53:31 +00001612bool SkCanvas::quickReject(const SkPath& path) const {
1613 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614}
1615
Mike Klein83c8dd92017-11-28 17:08:45 -05001616SkRect SkCanvas::getLocalClipBounds() const {
1617 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001618 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001619 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001620 }
1621
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001622 SkMatrix inverse;
1623 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001624 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001625 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001626 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001627
Mike Reed42e8c532017-01-23 14:09:13 -05001628 SkRect bounds;
1629 SkRect r;
1630 // adjust it outwards in case we are antialiasing
1631 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001632
Mike Reed42e8c532017-01-23 14:09:13 -05001633 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1634 ibounds.fRight + inset, ibounds.fBottom + inset);
1635 inverse.mapRect(&bounds, r);
1636 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001637}
1638
Mike Klein83c8dd92017-11-28 17:08:45 -05001639SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001640 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001641}
1642
reed@android.com8a1c16f2008-12-17 15:59:43 +00001643const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001644 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001645}
1646
Brian Osman11052242016-10-27 14:47:55 -04001647GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001648 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001649 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001650}
1651
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001652GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001653 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001654 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001655}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001656
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001657void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1658 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001659 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001660 if (outer.isEmpty()) {
1661 return;
1662 }
1663 if (inner.isEmpty()) {
1664 this->drawRRect(outer, paint);
1665 return;
1666 }
1667
1668 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001669 // be able to return ...
1670 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001671 //
1672 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001673 if (!outer.getBounds().contains(inner.getBounds())) {
1674 return;
1675 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001676
1677 this->onDrawDRRect(outer, inner, paint);
1678}
1679
reed41af9662015-01-05 07:49:08 -08001680void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001681 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001682 this->onDrawPaint(paint);
1683}
1684
1685void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001686 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001687 // To avoid redundant logic in our culling code and various backends, we always sort rects
1688 // before passing them along.
1689 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001690}
1691
msarettdca352e2016-08-26 06:37:45 -07001692void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001693 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001694 if (region.isEmpty()) {
1695 return;
1696 }
1697
1698 if (region.isRect()) {
1699 return this->drawIRect(region.getBounds(), paint);
1700 }
1701
1702 this->onDrawRegion(region, paint);
1703}
1704
reed41af9662015-01-05 07:49:08 -08001705void SkCanvas::drawOval(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->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001710}
1711
1712void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001713 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001714 this->onDrawRRect(rrect, paint);
1715}
1716
1717void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001718 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001719 this->onDrawPoints(mode, count, pts, paint);
1720}
1721
Mike Reede88a1cb2017-03-17 09:50:46 -04001722void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1723 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001724 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001725 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001726 this->onDrawVerticesObject(vertices.get(), mode, paint);
1727}
1728
1729void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001730 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001731 RETURN_ON_NULL(vertices);
1732 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001733}
1734
1735void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001736 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001737 this->onDrawPath(path, paint);
1738}
1739
reeda85d4d02015-05-06 12:56:48 -07001740void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001741 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001742 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001743 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001744}
1745
Mike Reedc4e31092018-01-30 11:15:27 -05001746// Returns true if the rect can be "filled" : non-empty and finite
1747static bool fillable(const SkRect& r) {
1748 SkScalar w = r.width();
1749 SkScalar h = r.height();
1750 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1751}
1752
reede47829b2015-08-06 10:02:53 -07001753void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1754 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001755 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001756 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001757 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001758 return;
1759 }
1760 this->onDrawImageRect(image, &src, dst, paint, constraint);
1761}
reed41af9662015-01-05 07:49:08 -08001762
reed84984ef2015-07-17 07:09:43 -07001763void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1764 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001765 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001766 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001767}
1768
reede47829b2015-08-06 10:02:53 -07001769void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1770 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001771 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001772 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1773 constraint);
1774}
reede47829b2015-08-06 10:02:53 -07001775
reed4c21dc52015-06-25 12:32:03 -07001776void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1777 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001778 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001779 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001780 if (dst.isEmpty()) {
1781 return;
1782 }
msarett552bca92016-08-03 06:53:26 -07001783 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1784 this->onDrawImageNine(image, center, dst, paint);
1785 } else {
reede47829b2015-08-06 10:02:53 -07001786 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001787 }
reed4c21dc52015-06-25 12:32:03 -07001788}
1789
msarett16882062016-08-16 09:31:08 -07001790void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1791 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001792 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001793 RETURN_ON_NULL(image);
1794 if (dst.isEmpty()) {
1795 return;
1796 }
msarett71df2d72016-09-30 12:41:42 -07001797
1798 SkIRect bounds;
1799 Lattice latticePlusBounds = lattice;
1800 if (!latticePlusBounds.fBounds) {
1801 bounds = SkIRect::MakeWH(image->width(), image->height());
1802 latticePlusBounds.fBounds = &bounds;
1803 }
1804
1805 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1806 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001807 } else {
1808 this->drawImageRect(image, dst, paint);
1809 }
1810}
1811
reed41af9662015-01-05 07:49:08 -08001812void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001813 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001814 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001815 return;
1816 }
reed41af9662015-01-05 07:49:08 -08001817 this->onDrawBitmap(bitmap, dx, dy, paint);
1818}
1819
reede47829b2015-08-06 10:02:53 -07001820void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001821 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001822 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001823 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001824 return;
1825 }
reede47829b2015-08-06 10:02:53 -07001826 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001827}
1828
reed84984ef2015-07-17 07:09:43 -07001829void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1830 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001831 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001832}
1833
reede47829b2015-08-06 10:02:53 -07001834void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1835 SrcRectConstraint constraint) {
1836 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1837 constraint);
1838}
reede47829b2015-08-06 10:02:53 -07001839
reed41af9662015-01-05 07:49:08 -08001840void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1841 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001842 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001843 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001844 return;
1845 }
msarett552bca92016-08-03 06:53:26 -07001846 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1847 this->onDrawBitmapNine(bitmap, center, dst, paint);
1848 } else {
reeda5517e22015-07-14 10:54:12 -07001849 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001850 }
reed41af9662015-01-05 07:49:08 -08001851}
1852
msarettc573a402016-08-02 08:05:56 -07001853void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1854 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001855 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001856 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001857 return;
1858 }
msarett71df2d72016-09-30 12:41:42 -07001859
1860 SkIRect bounds;
1861 Lattice latticePlusBounds = lattice;
1862 if (!latticePlusBounds.fBounds) {
1863 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1864 latticePlusBounds.fBounds = &bounds;
1865 }
1866
1867 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1868 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001869 } else {
msarett16882062016-08-16 09:31:08 -07001870 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001871 }
msarettc573a402016-08-02 08:05:56 -07001872}
1873
reed71c3c762015-06-24 10:29:17 -07001874void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001875 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001876 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001877 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001878 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001879 if (count <= 0) {
1880 return;
1881 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001882 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001883 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001884 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001885}
1886
reedf70b5312016-03-04 16:36:20 -08001887void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001888 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001889 if (key) {
1890 this->onDrawAnnotation(rect, key, value);
1891 }
1892}
1893
reede47829b2015-08-06 10:02:53 -07001894void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1895 const SkPaint* paint, SrcRectConstraint constraint) {
1896 if (src) {
1897 this->drawImageRect(image, *src, dst, paint, constraint);
1898 } else {
1899 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1900 dst, paint, constraint);
1901 }
1902}
1903void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1904 const SkPaint* paint, SrcRectConstraint constraint) {
1905 if (src) {
1906 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1907 } else {
1908 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1909 dst, paint, constraint);
1910 }
1911}
1912
Mike Reed4204da22017-05-17 08:53:36 -04001913void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001914 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001915 this->onDrawShadowRec(path, rec);
1916}
1917
1918void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1919 SkPaint paint;
1920 const SkRect& pathBounds = path.getBounds();
1921
1922 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1923 while (iter.next()) {
1924 iter.fDevice->drawShadow(path, rec);
1925 }
1926 LOOPER_END
1927}
1928
reed@android.com8a1c16f2008-12-17 15:59:43 +00001929//////////////////////////////////////////////////////////////////////////////
1930// These are the virtual drawing methods
1931//////////////////////////////////////////////////////////////////////////////
1932
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001933void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001934 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001935 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1936 }
1937}
1938
reed41af9662015-01-05 07:49:08 -08001939void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001940 this->internalDrawPaint(paint);
1941}
1942
1943void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001944 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001945
1946 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001947 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001948 }
1949
reed@google.com4e2b3d32011-04-07 14:18:59 +00001950 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001951}
1952
reed41af9662015-01-05 07:49:08 -08001953void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1954 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001955 if ((long)count <= 0) {
1956 return;
1957 }
1958
Mike Reed822128b2017-02-28 16:41:03 -05001959 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001960 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001961 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001962 // special-case 2 points (common for drawing a single line)
1963 if (2 == count) {
1964 r.set(pts[0], pts[1]);
1965 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001966 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001967 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001968 if (!r.isFinite()) {
1969 return;
1970 }
Mike Reed822128b2017-02-28 16:41:03 -05001971 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001972 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1973 return;
1974 }
1975 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001976 }
reed@google.coma584aed2012-05-16 14:06:02 +00001977
halcanary96fcdcc2015-08-27 07:41:13 -07001978 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001979
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001980 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001981
reed@android.com8a1c16f2008-12-17 15:59:43 +00001982 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001983 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001984 }
reed@google.com4b226022011-01-11 18:32:13 +00001985
reed@google.com4e2b3d32011-04-07 14:18:59 +00001986 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001987}
1988
reed4a167172016-08-18 17:15:25 -07001989static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1990 return ((intptr_t)paint.getImageFilter() |
1991#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1992 (intptr_t)canvas->getDrawFilter() |
1993#endif
1994 (intptr_t)paint.getLooper() ) != 0;
1995}
1996
reed41af9662015-01-05 07:49:08 -08001997void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001998 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002000 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002001 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002002 return;
2003 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004 }
reed@google.com4b226022011-01-11 18:32:13 +00002005
reed4a167172016-08-18 17:15:25 -07002006 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002007 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002008
reed4a167172016-08-18 17:15:25 -07002009 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002010 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002011 }
2012
2013 LOOPER_END
2014 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002015 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002016 SkDrawIter iter(this);
2017 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002018 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002019 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002020 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002021}
2022
msarett44df6512016-08-25 13:54:30 -07002023void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002024 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002025 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002026 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002027 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2028 return;
2029 }
msarett44df6512016-08-25 13:54:30 -07002030 }
2031
Mike Reed822128b2017-02-28 16:41:03 -05002032 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002033
2034 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002035 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002036 }
2037
2038 LOOPER_END
2039}
2040
reed41af9662015-01-05 07:49:08 -08002041void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002042 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002043 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002044 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002045 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002046 return;
2047 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002048 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002049
Mike Reed822128b2017-02-28 16:41:03 -05002050 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002051
2052 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002053 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002054 }
2055
2056 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002057}
2058
bsalomonac3aa242016-08-19 11:25:19 -07002059void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2060 SkScalar sweepAngle, bool useCenter,
2061 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002062 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002063 if (paint.canComputeFastBounds()) {
2064 SkRect storage;
2065 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002066 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002067 return;
2068 }
bsalomonac3aa242016-08-19 11:25:19 -07002069 }
2070
Mike Reed822128b2017-02-28 16:41:03 -05002071 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002072
2073 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002074 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002075 }
2076
2077 LOOPER_END
2078}
2079
reed41af9662015-01-05 07:49:08 -08002080void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002081 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002082 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002083 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2084 return;
2085 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002086 }
2087
2088 if (rrect.isRect()) {
2089 // call the non-virtual version
2090 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002091 return;
2092 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002093 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002094 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2095 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002096 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002097
Mike Reed822128b2017-02-28 16:41:03 -05002098 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002099
2100 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002101 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002102 }
2103
2104 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002105}
2106
Mike Reed822128b2017-02-28 16:41:03 -05002107void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002108 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002109 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002110 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2111 return;
2112 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002113 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002114
Mike Reed822128b2017-02-28 16:41:03 -05002115 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002116
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002117 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002118 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002119 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002120
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002121 LOOPER_END
2122}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002123
reed41af9662015-01-05 07:49:08 -08002124void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002125 if (!path.isFinite()) {
2126 return;
2127 }
2128
Mike Reed822128b2017-02-28 16:41:03 -05002129 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002130 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002131 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002132 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2133 return;
2134 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002135 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002136
Mike Reed822128b2017-02-28 16:41:03 -05002137 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002138 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002139 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002140 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002141 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002142 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002143
Mike Reed822128b2017-02-28 16:41:03 -05002144 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145
2146 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002147 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002148 }
2149
reed@google.com4e2b3d32011-04-07 14:18:59 +00002150 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151}
2152
reed262a71b2015-12-05 13:07:27 -08002153bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002154 if (!paint.getImageFilter()) {
2155 return false;
2156 }
2157
2158 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002159 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002160 return false;
2161 }
2162
2163 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2164 // Once we can filter and the filter will return a result larger than itself, we should be
2165 // able to remove this constraint.
2166 // skbug.com/4526
2167 //
2168 SkPoint pt;
2169 ctm.mapXY(x, y, &pt);
2170 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2171 return ir.contains(fMCRec->fRasterClip.getBounds());
2172}
2173
reeda85d4d02015-05-06 12:56:48 -07002174void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07002175 SkRect bounds = SkRect::MakeXYWH(x, y,
2176 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002177 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002178 SkRect tmp = bounds;
2179 if (paint) {
2180 paint->computeFastBounds(tmp, &tmp);
2181 }
2182 if (this->quickReject(tmp)) {
2183 return;
2184 }
reeda85d4d02015-05-06 12:56:48 -07002185 }
halcanary9d524f22016-03-29 09:03:52 -07002186
reeda85d4d02015-05-06 12:56:48 -07002187 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002188 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002189 paint = lazy.init();
2190 }
reed262a71b2015-12-05 13:07:27 -08002191
reeda2217ef2016-07-20 06:04:34 -07002192 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002193 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2194 *paint);
2195 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002196 special = this->getDevice()->makeSpecial(image);
2197 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002198 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002199 }
2200 }
2201
reed262a71b2015-12-05 13:07:27 -08002202 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2203
reeda85d4d02015-05-06 12:56:48 -07002204 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002205 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002206 if (special) {
2207 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002208 iter.fDevice->ctm().mapXY(x, y, &pt);
2209 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002210 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002211 SkScalarRoundToInt(pt.fY), pnt,
2212 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002213 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002214 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002215 }
reeda85d4d02015-05-06 12:56:48 -07002216 }
halcanary9d524f22016-03-29 09:03:52 -07002217
reeda85d4d02015-05-06 12:56:48 -07002218 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002219}
2220
reed41af9662015-01-05 07:49:08 -08002221void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002222 const SkPaint* paint, SrcRectConstraint constraint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002223 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002224 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002225 if (paint) {
2226 paint->computeFastBounds(dst, &storage);
2227 }
2228 if (this->quickReject(storage)) {
2229 return;
2230 }
reeda85d4d02015-05-06 12:56:48 -07002231 }
2232 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002233 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002234 paint = lazy.init();
2235 }
halcanary9d524f22016-03-29 09:03:52 -07002236
senorblancoc41e7e12015-12-07 12:51:30 -08002237 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002238 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002239
reeda85d4d02015-05-06 12:56:48 -07002240 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002241 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002242 }
halcanary9d524f22016-03-29 09:03:52 -07002243
reeda85d4d02015-05-06 12:56:48 -07002244 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002245}
2246
reed41af9662015-01-05 07:49:08 -08002247void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002248 SkDEBUGCODE(bitmap.validate();)
2249
reed33366972015-10-08 09:22:02 -07002250 if (bitmap.drawsNothing()) {
2251 return;
2252 }
2253
2254 SkLazyPaint lazy;
2255 if (nullptr == paint) {
2256 paint = lazy.init();
2257 }
2258
Mike Reed822128b2017-02-28 16:41:03 -05002259 SkRect bounds;
2260 bitmap.getBounds(&bounds);
2261 bounds.offset(x, y);
2262 bool canFastBounds = paint->canComputeFastBounds();
2263 if (canFastBounds) {
2264 SkRect storage;
2265 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002266 return;
2267 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002268 }
reed@google.com4b226022011-01-11 18:32:13 +00002269
reeda2217ef2016-07-20 06:04:34 -07002270 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002271 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2272 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002273 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002274 special = this->getDevice()->makeSpecial(bitmap);
2275 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002276 drawAsSprite = false;
2277 }
2278 }
2279
Mike Reed822128b2017-02-28 16:41:03 -05002280 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002281
2282 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002283 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002284 if (special) {
reed262a71b2015-12-05 13:07:27 -08002285 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002286 iter.fDevice->ctm().mapXY(x, y, &pt);
2287 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002288 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002289 SkScalarRoundToInt(pt.fY), pnt,
2290 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002291 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002292 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002293 }
reed33366972015-10-08 09:22:02 -07002294 }
msarettfbfa2582016-08-12 08:29:08 -07002295
reed33366972015-10-08 09:22:02 -07002296 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002297}
2298
reed@google.com9987ec32011-09-07 11:57:52 +00002299// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002300void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002301 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002302 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002303 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002304 return;
2305 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002306
halcanary96fcdcc2015-08-27 07:41:13 -07002307 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002308 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002309 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2310 return;
2311 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002312 }
reed@google.com3d608122011-11-21 15:16:16 +00002313
reed@google.com33535f32012-09-25 15:37:50 +00002314 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002315 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002316 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002317 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002318
senorblancoc41e7e12015-12-07 12:51:30 -08002319 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002320 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002321
reed@google.com33535f32012-09-25 15:37:50 +00002322 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002323 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002324 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002325
reed@google.com33535f32012-09-25 15:37:50 +00002326 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002327}
2328
reed41af9662015-01-05 07:49:08 -08002329void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002330 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002331 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002332 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002333}
2334
reed4c21dc52015-06-25 12:32:03 -07002335void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2336 const SkPaint* paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002337 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002338 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002339 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2340 return;
2341 }
reed@google.com3d608122011-11-21 15:16:16 +00002342 }
halcanary9d524f22016-03-29 09:03:52 -07002343
reed4c21dc52015-06-25 12:32:03 -07002344 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002345 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002346 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002347 }
halcanary9d524f22016-03-29 09:03:52 -07002348
senorblancoc41e7e12015-12-07 12:51:30 -08002349 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002350
reed4c21dc52015-06-25 12:32:03 -07002351 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002352 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002353 }
halcanary9d524f22016-03-29 09:03:52 -07002354
reed4c21dc52015-06-25 12:32:03 -07002355 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002356}
2357
reed41af9662015-01-05 07:49:08 -08002358void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2359 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002360 SkDEBUGCODE(bitmap.validate();)
2361
halcanary96fcdcc2015-08-27 07:41:13 -07002362 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002363 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002364 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2365 return;
2366 }
reed4c21dc52015-06-25 12:32:03 -07002367 }
halcanary9d524f22016-03-29 09:03:52 -07002368
reed4c21dc52015-06-25 12:32:03 -07002369 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002370 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002371 paint = lazy.init();
2372 }
halcanary9d524f22016-03-29 09:03:52 -07002373
senorblancoc41e7e12015-12-07 12:51:30 -08002374 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002375
reed4c21dc52015-06-25 12:32:03 -07002376 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002377 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002378 }
halcanary9d524f22016-03-29 09:03:52 -07002379
reed4c21dc52015-06-25 12:32:03 -07002380 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002381}
2382
msarett16882062016-08-16 09:31:08 -07002383void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2384 const SkPaint* paint) {
2385 if (nullptr == paint || paint->canComputeFastBounds()) {
2386 SkRect storage;
2387 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2388 return;
2389 }
2390 }
2391
2392 SkLazyPaint lazy;
2393 if (nullptr == paint) {
2394 paint = lazy.init();
2395 }
2396
2397 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2398
2399 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002400 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002401 }
2402
2403 LOOPER_END
2404}
2405
2406void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2407 const SkRect& dst, const SkPaint* paint) {
2408 if (nullptr == paint || paint->canComputeFastBounds()) {
2409 SkRect storage;
2410 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2411 return;
2412 }
2413 }
2414
2415 SkLazyPaint lazy;
2416 if (nullptr == paint) {
2417 paint = lazy.init();
2418 }
2419
2420 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2421
2422 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002423 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002424 }
2425
2426 LOOPER_END
2427}
2428
reed@google.comf67e4cf2011-03-15 20:56:58 +00002429class SkDeviceFilteredPaint {
2430public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002431 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002432 uint32_t filteredFlags = device->filterTextFlags(paint);
2433 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002434 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002435 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002436 fPaint = newPaint;
2437 } else {
2438 fPaint = &paint;
2439 }
2440 }
2441
reed@google.comf67e4cf2011-03-15 20:56:58 +00002442 const SkPaint& paint() const { return *fPaint; }
2443
2444private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002445 const SkPaint* fPaint;
2446 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002447};
2448
reed@google.come0d9ce82014-04-23 04:00:17 +00002449void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2450 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002451 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002452
2453 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002454 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002455 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002456 }
2457
reed@google.com4e2b3d32011-04-07 14:18:59 +00002458 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459}
2460
reed@google.come0d9ce82014-04-23 04:00:17 +00002461void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2462 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002463 SkPoint textOffset = SkPoint::Make(0, 0);
2464
halcanary96fcdcc2015-08-27 07:41:13 -07002465 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002466
reed@android.com8a1c16f2008-12-17 15:59:43 +00002467 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002468 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002469 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002470 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002471 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002472
reed@google.com4e2b3d32011-04-07 14:18:59 +00002473 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474}
2475
reed@google.come0d9ce82014-04-23 04:00:17 +00002476void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2477 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002478
2479 SkPoint textOffset = SkPoint::Make(0, constY);
2480
halcanary96fcdcc2015-08-27 07:41:13 -07002481 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002482
reed@android.com8a1c16f2008-12-17 15:59:43 +00002483 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002484 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002485 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002486 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002487 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002488
reed@google.com4e2b3d32011-04-07 14:18:59 +00002489 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002490}
2491
reed@google.come0d9ce82014-04-23 04:00:17 +00002492void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2493 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002494 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002495
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002497 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002498 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002499 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002500
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002501 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002502}
2503
reed45561a02016-07-07 12:47:17 -07002504void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2505 const SkRect* cullRect, const SkPaint& paint) {
2506 if (cullRect && this->quickReject(*cullRect)) {
2507 return;
2508 }
2509
2510 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2511
2512 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002513 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002514 }
2515
2516 LOOPER_END
2517}
2518
fmalita00d5c2c2014-08-21 08:53:26 -07002519void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2520 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002521
fmalita85d5eb92015-03-04 11:20:12 -08002522 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002523 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002524 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002525 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002526 SkRect tmp;
2527 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2528 return;
2529 }
2530 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002531 }
2532
fmalita024f9962015-03-03 19:08:17 -08002533 // We cannot filter in the looper as we normally do, because the paint is
2534 // incomplete at this point (text-related attributes are embedded within blob run paints).
2535 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002536 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002537
fmalita85d5eb92015-03-04 11:20:12 -08002538 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002539
fmalitaaa1b9122014-08-28 14:32:24 -07002540 while (iter.next()) {
2541 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002542 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002543 }
2544
fmalitaaa1b9122014-08-28 14:32:24 -07002545 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002546
2547 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002548}
2549
Cary Clark2a475ea2017-04-28 15:35:12 -04002550void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2551 this->drawText(string.c_str(), string.size(), x, y, paint);
2552}
2553
reed@google.come0d9ce82014-04-23 04:00:17 +00002554// These will become non-virtual, so they always call the (virtual) onDraw... method
2555void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2556 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002557 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002558 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002559 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002560 this->onDrawText(text, byteLength, x, y, paint);
2561 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002562}
2563void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2564 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002565 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002566 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002567 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002568 this->onDrawPosText(text, byteLength, pos, paint);
2569 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002570}
2571void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2572 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002573 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002574 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002575 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002576 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2577 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002578}
2579void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2580 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002581 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002582 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002583 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002584 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2585 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002586}
reed45561a02016-07-07 12:47:17 -07002587void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2588 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002589 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002590 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002591 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002592 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2593 }
2594}
fmalita00d5c2c2014-08-21 08:53:26 -07002595void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2596 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002597 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002598 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002599 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002600 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002601}
reed@google.come0d9ce82014-04-23 04:00:17 +00002602
Mike Reede88a1cb2017-03-17 09:50:46 -04002603void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2604 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002605 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2606
2607 while (iter.next()) {
2608 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002609 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002610 }
2611
2612 LOOPER_END
2613}
2614
dandovb3c9d1c2014-08-12 08:34:29 -07002615void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002616 const SkPoint texCoords[4], SkBlendMode bmode,
2617 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002618 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002619 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002620 return;
2621 }
mtklein6cfa73a2014-08-13 13:33:49 -07002622
Mike Reedfaba3712016-11-03 14:45:31 -04002623 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002624}
2625
2626void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002627 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002628 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002629 // Since a patch is always within the convex hull of the control points, we discard it when its
2630 // bounding rectangle is completely outside the current clip.
2631 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002632 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002633 if (this->quickReject(bounds)) {
2634 return;
2635 }
mtklein6cfa73a2014-08-13 13:33:49 -07002636
Mike Reed435071e2017-05-23 11:22:56 -04002637 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2638
halcanary96fcdcc2015-08-27 07:41:13 -07002639 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002640
dandovecfff212014-08-04 10:02:00 -07002641 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002642 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002643 }
mtklein6cfa73a2014-08-13 13:33:49 -07002644
dandovecfff212014-08-04 10:02:00 -07002645 LOOPER_END
2646}
2647
reeda8db7282015-07-07 10:22:31 -07002648void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002649#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002650 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002651#endif
reede3b38ce2016-01-08 09:18:44 -08002652 RETURN_ON_NULL(dr);
2653 if (x || y) {
2654 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2655 this->onDrawDrawable(dr, &matrix);
2656 } else {
2657 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002658 }
2659}
2660
reeda8db7282015-07-07 10:22:31 -07002661void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002662#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002663 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002664#endif
reede3b38ce2016-01-08 09:18:44 -08002665 RETURN_ON_NULL(dr);
2666 if (matrix && matrix->isIdentity()) {
2667 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002668 }
reede3b38ce2016-01-08 09:18:44 -08002669 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002670}
2671
2672void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002673 // drawable bounds are no longer reliable (e.g. android displaylist)
2674 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002675 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002676}
2677
reed71c3c762015-06-24 10:29:17 -07002678void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002679 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002680 const SkRect* cull, const SkPaint* paint) {
2681 if (cull && this->quickReject(*cull)) {
2682 return;
2683 }
2684
2685 SkPaint pnt;
2686 if (paint) {
2687 pnt = *paint;
2688 }
halcanary9d524f22016-03-29 09:03:52 -07002689
halcanary96fcdcc2015-08-27 07:41:13 -07002690 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002691 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002692 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002693 }
2694 LOOPER_END
2695}
2696
reedf70b5312016-03-04 16:36:20 -08002697void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2698 SkASSERT(key);
2699
2700 SkPaint paint;
2701 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2702 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002703 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002704 }
2705 LOOPER_END
2706}
2707
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708//////////////////////////////////////////////////////////////////////////////
2709// These methods are NOT virtual, and therefore must call back into virtual
2710// methods, rather than actually drawing themselves.
2711//////////////////////////////////////////////////////////////////////////////
2712
reed374772b2016-10-05 17:33:02 -07002713void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002715 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002716 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002717 this->drawPaint(paint);
2718}
2719
2720void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002721 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002722 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2723}
2724
Mike Reed3661bc92017-02-22 13:21:42 -05002725void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 pts[0].set(x0, y0);
2728 pts[1].set(x1, y1);
2729 this->drawPoints(kLines_PointMode, 2, pts, paint);
2730}
2731
Mike Reed3661bc92017-02-22 13:21:42 -05002732void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002733 if (radius < 0) {
2734 radius = 0;
2735 }
2736
2737 SkRect r;
2738 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002739 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740}
2741
2742void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2743 const SkPaint& paint) {
2744 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002745 SkRRect rrect;
2746 rrect.setRectXY(r, rx, ry);
2747 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748 } else {
2749 this->drawRect(r, paint);
2750 }
2751}
2752
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2754 SkScalar sweepAngle, bool useCenter,
2755 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002756 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002757 if (oval.isEmpty() || !sweepAngle) {
2758 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002759 }
bsalomon21af9ca2016-08-25 12:29:23 -07002760 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002761}
2762
2763void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2764 const SkPath& path, SkScalar hOffset,
2765 SkScalar vOffset, const SkPaint& paint) {
2766 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002767
reed@android.com8a1c16f2008-12-17 15:59:43 +00002768 matrix.setTranslate(hOffset, vOffset);
2769 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2770}
2771
reed@android.comf76bacf2009-05-13 14:00:33 +00002772///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002773
Mike Klein88d90712018-01-27 17:30:04 +00002774/**
2775 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2776 * against the playback cost of recursing into the subpicture to get at its actual ops.
2777 *
2778 * For now we pick a conservatively small value, though measurement (and other heuristics like
2779 * the type of ops contained) may justify changing this value.
2780 */
2781#define kMaxPictureOpsToUnrollInsteadOfRef 1
2782
reedd5fa1a42014-08-09 11:08:05 -07002783void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002784 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002785 RETURN_ON_NULL(picture);
2786
reede3b38ce2016-01-08 09:18:44 -08002787 if (matrix && matrix->isIdentity()) {
2788 matrix = nullptr;
2789 }
Mike Klein88d90712018-01-27 17:30:04 +00002790 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2791 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2792 picture->playback(this);
2793 } else {
2794 this->onDrawPicture(picture, matrix, paint);
2795 }
reedd5fa1a42014-08-09 11:08:05 -07002796}
robertphillips9b14f262014-06-04 05:40:44 -07002797
reedd5fa1a42014-08-09 11:08:05 -07002798void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2799 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002800 if (!paint || paint->canComputeFastBounds()) {
2801 SkRect bounds = picture->cullRect();
2802 if (paint) {
2803 paint->computeFastBounds(bounds, &bounds);
2804 }
2805 if (matrix) {
2806 matrix->mapRect(&bounds);
2807 }
2808 if (this->quickReject(bounds)) {
2809 return;
2810 }
2811 }
2812
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002813 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002814 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002815}
2816
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817///////////////////////////////////////////////////////////////////////////////
2818///////////////////////////////////////////////////////////////////////////////
2819
reed3aafe112016-08-18 12:45:34 -07002820SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002821 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002822
2823 SkASSERT(canvas);
2824
reed3aafe112016-08-18 12:45:34 -07002825 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826 fDone = !fImpl->next();
2827}
2828
2829SkCanvas::LayerIter::~LayerIter() {
2830 fImpl->~SkDrawIter();
2831}
2832
2833void SkCanvas::LayerIter::next() {
2834 fDone = !fImpl->next();
2835}
2836
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002837SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002838 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839}
2840
2841const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002842 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002843}
2844
2845const SkPaint& SkCanvas::LayerIter::paint() const {
2846 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002847 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002848 paint = &fDefaultPaint;
2849 }
2850 return *paint;
2851}
2852
Mike Reeda1361362017-03-07 09:37:29 -05002853void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2854 return fImpl->fDevice->onAsRgnClip(rgn);
2855}
2856
reed@android.com8a1c16f2008-12-17 15:59:43 +00002857int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2858int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002859
2860///////////////////////////////////////////////////////////////////////////////
2861
Brian Osman10fc6fd2018-03-02 11:01:10 -05002862// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002863static bool supported_for_raster_canvas(const SkImageInfo& info) {
2864 switch (info.alphaType()) {
2865 case kPremul_SkAlphaType:
2866 case kOpaque_SkAlphaType:
2867 break;
2868 default:
2869 return false;
2870 }
2871
2872 switch (info.colorType()) {
2873 case kAlpha_8_SkColorType:
2874 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002875 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002876 case kRGBA_F16_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002877 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002878 break;
2879 default:
2880 return false;
2881 }
2882
2883 return true;
2884}
2885
Mike Reed5df49342016-11-12 08:06:55 -06002886std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002887 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002888 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002889 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002890 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002891
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002892 SkBitmap bitmap;
2893 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002894 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002895 }
Mike Reed12f77342017-11-08 11:19:52 -05002896
2897 return props ?
2898 skstd::make_unique<SkCanvas>(bitmap, *props) :
2899 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002900}
reedd5fa1a42014-08-09 11:08:05 -07002901
2902///////////////////////////////////////////////////////////////////////////////
2903
Florin Malitaee424ac2016-12-01 12:47:59 -05002904SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2905 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2906
Florin Malita439ace92016-12-02 12:05:41 -05002907SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2908 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2909
Florin Malitaee424ac2016-12-01 12:47:59 -05002910SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2911 (void)this->INHERITED::getSaveLayerStrategy(rec);
2912 return kNoLayer_SaveLayerStrategy;
2913}
2914
2915///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002916
reed73603f32016-09-20 08:42:38 -07002917static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2918static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2919static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2920static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2921static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2922static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002923
2924///////////////////////////////////////////////////////////////////////////////////////////////////
2925
2926SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2927 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002928 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002929 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2930 SkIPoint origin = dev->getOrigin();
2931 SkMatrix ctm = this->getTotalMatrix();
2932 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2933
2934 SkIRect clip = fMCRec->fRasterClip.getBounds();
2935 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002936 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002937 clip.setEmpty();
2938 }
2939
2940 fAllocator->updateHandle(handle, ctm, clip);
2941 return handle;
2942 }
2943 return nullptr;
2944}
2945
2946static bool install(SkBitmap* bm, const SkImageInfo& info,
2947 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002948 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002949}
2950
2951SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2952 SkBitmap* bm) {
2953 SkRasterHandleAllocator::Rec rec;
2954 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2955 return nullptr;
2956 }
2957 return rec.fHandle;
2958}
2959
2960std::unique_ptr<SkCanvas>
2961SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2962 const SkImageInfo& info, const Rec* rec) {
2963 if (!alloc || !supported_for_raster_canvas(info)) {
2964 return nullptr;
2965 }
2966
2967 SkBitmap bm;
2968 Handle hndl;
2969
2970 if (rec) {
2971 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2972 } else {
2973 hndl = alloc->allocBitmap(info, &bm);
2974 }
2975 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2976}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002977
2978///////////////////////////////////////////////////////////////////////////////////////////////////
2979
2980