blob: 5e33dbf3716707d2cb0bbcefba09371a56b21289 [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"
Florin Malitaee424ac2016-12-01 12:47:59 -050026#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070027#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070028#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070029#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000030#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000031#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050032#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000033#include "SkRRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080034#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040035#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000036#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070037#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000038#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000039#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080040#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070041#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000042
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000043#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080044#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#include "GrRenderTarget.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)
53
Mike Reed139e5e02017-03-08 11:29:33 -050054class SkNoPixelsDevice : public SkBaseDevice {
55public:
56 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
57 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
Mike Reed566e53c2017-03-10 10:49:45 -050058 {
Mike Reede393a622017-03-10 16:35:25 -050059 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
60 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050061 }
Mike Reed139e5e02017-03-08 11:29:33 -050062
63 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050064 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050065 this->privateResize(bounds.width(), bounds.height());
66 }
67
68protected:
69 // We don't track the clip at all (for performance), but we have to respond to some queries.
70 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
71 void onSave() override {}
72 void onRestore() override {}
73 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
74 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
75 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
76 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
77 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
78 bool onClipIsAA() const override { return false; }
79 void onAsRgnClip(SkRegion* rgn) const override {
80 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
81 }
82 ClipType onGetClipType() const override {
83 return kRect_ClipType;
84 }
85
86 void drawPaint(const SkPaint& paint) override {}
87 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
88 void drawRect(const SkRect&, const SkPaint&) override {}
89 void drawOval(const SkRect&, const SkPaint&) override {}
90 void drawRRect(const SkRRect&, const SkPaint&) override {}
91 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
92 void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {}
93 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
94 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
95 SkCanvas::SrcRectConstraint) override {}
96 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
97 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
98 const SkPaint&) override {}
99 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
Mike Reed2f6b5a42017-03-19 15:04:17 -0400100 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -0500101
102private:
103 typedef SkBaseDevice INHERITED;
104};
105
106///////////////////////////////////////////////////////////////////////////////////////////////////
107
reedc83a2972015-07-16 07:40:45 -0700108/*
109 * Return true if the drawing this rect would hit every pixels in the canvas.
110 *
111 * Returns false if
112 * - rect does not contain the canvas' bounds
113 * - paint is not fill
114 * - paint would blur or otherwise change the coverage of the rect
115 */
116bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
117 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700118 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
119 (int)kNone_ShaderOverrideOpacity,
120 "need_matching_enums0");
121 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
122 (int)kOpaque_ShaderOverrideOpacity,
123 "need_matching_enums1");
124 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
125 (int)kNotOpaque_ShaderOverrideOpacity,
126 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700127
128 const SkISize size = this->getBaseLayerSize();
129 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500130
131 // if we're clipped at all, we can't overwrite the entire surface
132 {
133 SkBaseDevice* base = this->getDevice();
134 SkBaseDevice* top = this->getTopDevice();
135 if (base != top) {
136 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
137 }
138 if (!base->clipIsWideOpen()) {
139 return false;
140 }
reedc83a2972015-07-16 07:40:45 -0700141 }
142
143 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700144 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700145 return false; // conservative
146 }
halcanaryc5769b22016-08-10 07:13:21 -0700147
148 SkRect devRect;
149 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
150 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700151 return false;
152 }
153 }
154
155 if (paint) {
156 SkPaint::Style paintStyle = paint->getStyle();
157 if (!(paintStyle == SkPaint::kFill_Style ||
158 paintStyle == SkPaint::kStrokeAndFill_Style)) {
159 return false;
160 }
161 if (paint->getMaskFilter() || paint->getLooper()
162 || paint->getPathEffect() || paint->getImageFilter()) {
163 return false; // conservative
164 }
165 }
166 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
167}
168
169///////////////////////////////////////////////////////////////////////////////////////////////////
170
reedd990e2f2014-12-22 11:58:30 -0800171static bool gIgnoreSaveLayerBounds;
172void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
173 gIgnoreSaveLayerBounds = ignore;
174}
175bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
176 return gIgnoreSaveLayerBounds;
177}
178
reed0acf1b42014-12-22 16:12:38 -0800179static bool gTreatSpriteAsBitmap;
180void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
181 gTreatSpriteAsBitmap = spriteAsBitmap;
182}
183bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
184 return gTreatSpriteAsBitmap;
185}
186
reed@google.comda17f752012-08-16 18:27:05 +0000187// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188//#define SK_TRACE_SAVERESTORE
189
190#ifdef SK_TRACE_SAVERESTORE
191 static int gLayerCounter;
192 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
193 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
194
195 static int gRecCounter;
196 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
197 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
198
199 static int gCanvasCounter;
200 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
201 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
202#else
203 #define inc_layer()
204 #define dec_layer()
205 #define inc_rec()
206 #define dec_rec()
207 #define inc_canvas()
208 #define dec_canvas()
209#endif
210
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000211typedef SkTLazy<SkPaint> SkLazyPaint;
212
reedc83a2972015-07-16 07:40:45 -0700213void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000214 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700215 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
216 ? SkSurface::kDiscard_ContentChangeMode
217 : SkSurface::kRetain_ContentChangeMode);
218 }
219}
220
221void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
222 ShaderOverrideOpacity overrideOpacity) {
223 if (fSurfaceBase) {
224 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
225 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
226 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
227 // and therefore we don't care which mode we're in.
228 //
229 if (fSurfaceBase->outstandingImageSnapshot()) {
230 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
231 mode = SkSurface::kDiscard_ContentChangeMode;
232 }
233 }
234 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000235 }
236}
237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000240/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 The clip/matrix/proc are fields that reflect the top of the save/restore
242 stack. Whenever the canvas changes, it marks a dirty flag, and then before
243 these are used (assuming we're not on a layer) we rebuild these cache
244 values: they reflect the top of the save stack, but translated and clipped
245 by the device's XY offset and bitmap-bounds.
246*/
247struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400248 DeviceCM* fNext;
249 sk_sp<SkBaseDevice> fDevice;
250 SkRasterClip fClip;
251 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
252 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400253 sk_sp<SkImage> fClipImage;
254 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255
Florin Malita53f77bd2017-04-28 13:48:37 -0400256 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000257 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700258 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400259 , fDevice(std::move(device))
260 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700261 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000262 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400263 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400264 {}
reed@google.com4b226022011-01-11 18:32:13 +0000265
mtkleinfeaadee2015-04-08 11:25:48 -0700266 void reset(const SkIRect& bounds) {
267 SkASSERT(!fPaint);
268 SkASSERT(!fNext);
269 SkASSERT(fDevice);
270 fClip.setRect(bounds);
271 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272};
273
274/* This is the record we keep for each save/restore level in the stack.
275 Since a level optionally copies the matrix and/or stack, we have pointers
276 for these fields. If the value is copied for this level, the copy is
277 stored in the ...Storage field, and the pointer points to that. If the
278 value is not copied for this level, we ignore ...Storage, and just point
279 at the corresponding value in the previous level in the stack.
280*/
281class SkCanvas::MCRec {
282public:
reed1f836ee2014-07-07 07:49:34 -0700283 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700284 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 /* If there are any layers in the stack, this points to the top-most
286 one that is at or below this level in the stack (so we know what
287 bitmap/device to draw into from this level. This value is NOT
288 reference counted, since the real owner is either our fLayer field,
289 or a previous one in a lower level.)
290 */
Mike Reeda1361362017-03-07 09:37:29 -0500291 DeviceCM* fTopLayer;
292 SkConservativeClip fRasterClip;
293 SkMatrix fMatrix;
294 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295
Mike Reeda1361362017-03-07 09:37:29 -0500296 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700297 fFilter = nullptr;
298 fLayer = nullptr;
299 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800300 fMatrix.reset();
301 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700302
reedd9544982014-09-09 18:46:22 -0700303 // don't bother initializing fNext
304 inc_rec();
305 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400306 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700307 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700308 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700309 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800310 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700311
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312 // don't bother initializing fNext
313 inc_rec();
314 }
315 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000316 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700317 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000318 dec_rec();
319 }
mtkleinfeaadee2015-04-08 11:25:48 -0700320
321 void reset(const SkIRect& bounds) {
322 SkASSERT(fLayer);
323 SkASSERT(fDeferredSaveCount == 0);
324
325 fMatrix.reset();
326 fRasterClip.setRect(bounds);
327 fLayer->reset(bounds);
328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329};
330
Mike Reeda1361362017-03-07 09:37:29 -0500331class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332public:
Mike Reeda1361362017-03-07 09:37:29 -0500333 SkDrawIter(SkCanvas* canvas)
334 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
335 {}
reed@google.com4b226022011-01-11 18:32:13 +0000336
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000338 const DeviceCM* rec = fCurrLayer;
339 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400340 fDevice = rec->fDevice.get();
341 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700343 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 return true;
345 }
346 return false;
347 }
reed@google.com4b226022011-01-11 18:32:13 +0000348
reed@google.com6f8f2922011-03-04 22:27:10 +0000349 int getX() const { return fDevice->getOrigin().x(); }
350 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000352
Mike Reed99330ba2017-02-22 11:01:08 -0500353 SkBaseDevice* fDevice;
354
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 const DeviceCM* fCurrLayer;
357 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358};
359
Florin Malita713b8ef2017-04-28 10:57:24 -0400360#define FOR_EACH_TOP_DEVICE( code ) \
361 do { \
362 DeviceCM* layer = fMCRec->fTopLayer; \
363 while (layer) { \
364 SkBaseDevice* device = layer->fDevice.get(); \
365 if (device) { \
366 code; \
367 } \
368 layer = layer->fNext; \
369 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500370 } while (0)
371
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372/////////////////////////////////////////////////////////////////////////////
373
reeddbc3cef2015-04-29 12:18:57 -0700374static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
375 return lazy->isValid() ? lazy->get() : lazy->set(orig);
376}
377
378/**
379 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700380 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700381 */
reedd053ce92016-03-22 10:17:23 -0700382static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700383 SkImageFilter* imgf = paint.getImageFilter();
384 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700385 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700386 }
387
reedd053ce92016-03-22 10:17:23 -0700388 SkColorFilter* imgCFPtr;
389 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700390 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700391 }
reedd053ce92016-03-22 10:17:23 -0700392 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700393
394 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700395 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700396 // there is no existing paint colorfilter, so we can just return the imagefilter's
397 return imgCF;
398 }
399
400 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
401 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700402 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700403}
404
senorblanco87e066e2015-10-28 11:23:36 -0700405/**
406 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
407 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
408 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
409 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
410 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
411 * conservative "effective" bounds based on the settings in the paint... with one exception. This
412 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
413 * deliberately ignored.
414 */
415static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
416 const SkRect& rawBounds,
417 SkRect* storage) {
418 SkPaint tmpUnfiltered(paint);
419 tmpUnfiltered.setImageFilter(nullptr);
420 if (tmpUnfiltered.canComputeFastBounds()) {
421 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
422 } else {
423 return rawBounds;
424 }
425}
426
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427class AutoDrawLooper {
428public:
senorblanco87e066e2015-10-28 11:23:36 -0700429 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
430 // paint. It's used to determine the size of the offscreen layer for filters.
431 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700432 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700433 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000434 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800435#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800437#else
438 fFilter = nullptr;
439#endif
reed4a8126e2014-09-22 07:29:03 -0700440 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000441 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700442 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000443 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444
reedd053ce92016-03-22 10:17:23 -0700445 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700446 if (simplifiedCF) {
447 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700448 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700449 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700450 fPaint = paint;
451 }
452
453 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700454 /**
455 * We implement ImageFilters for a given draw by creating a layer, then applying the
456 * imagefilter to the pixels of that layer (its backing surface/image), and then
457 * we call restore() to xfer that layer to the main canvas.
458 *
459 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
460 * 2. Generate the src pixels:
461 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
462 * return (fPaint). We then draw the primitive (using srcover) into a cleared
463 * buffer/surface.
464 * 3. Restore the layer created in #1
465 * The imagefilter is passed the buffer/surface from the layer (now filled with the
466 * src pixels of the primitive). It returns a new "filtered" buffer, which we
467 * draw onto the previous layer using the xfermode from the original paint.
468 */
reed@google.com8926b162012-03-23 15:36:36 +0000469 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500470 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700471 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700472 SkRect storage;
473 if (rawBounds) {
474 // Make rawBounds include all paint outsets except for those due to image filters.
475 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
476 }
reedbfd5f172016-01-07 11:28:08 -0800477 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700478 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700479 fTempLayerForImageFilter = true;
480 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000481 }
482
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000483 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500484 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000485 fIsSimple = false;
486 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700487 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000488 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700489 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000490 }
491 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000492
reed@android.com8a1c16f2008-12-17 15:59:43 +0000493 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700494 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000495 fCanvas->internalRestore();
496 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000497 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000499
reed@google.com4e2b3d32011-04-07 14:18:59 +0000500 const SkPaint& paint() const {
501 SkASSERT(fPaint);
502 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000504
reed@google.com129ec222012-05-15 13:24:09 +0000505 bool next(SkDrawFilter::Type drawType) {
506 if (fDone) {
507 return false;
508 } else if (fIsSimple) {
509 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000510 return !fPaint->nothingToDraw();
511 } else {
512 return this->doNext(drawType);
513 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500517 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700518 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000519 SkCanvas* fCanvas;
520 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000521 SkDrawFilter* fFilter;
522 const SkPaint* fPaint;
523 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700524 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000525 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000526 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000527 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500528 char fStorage[48];
529 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000530
531 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532};
533
reed@google.com129ec222012-05-15 13:24:09 +0000534bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700535 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000536 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700537 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000538
reeddbc3cef2015-04-29 12:18:57 -0700539 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
540 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000541
reed5c476fb2015-04-20 08:04:21 -0700542 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700543 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700544 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000545 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000546
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000547 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000548 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000549 return false;
550 }
551 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000552 if (!fFilter->filter(paint, drawType)) {
553 fDone = true;
554 return false;
555 }
halcanary96fcdcc2015-08-27 07:41:13 -0700556 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000557 // no looper means we only draw once
558 fDone = true;
559 }
560 }
561 fPaint = paint;
562
563 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000564 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000565 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000566 }
567
568 // call this after any possible paint modifiers
569 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700570 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000571 return false;
572 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000573 return true;
574}
575
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576////////// macros to place around the internal draw calls //////////////////
577
reed3aafe112016-08-18 12:45:34 -0700578#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
579 this->predrawNotify(); \
580 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
581 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800582 SkDrawIter iter(this);
583
584
reed@google.com8926b162012-03-23 15:36:36 +0000585#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000586 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700587 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000588 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000589 SkDrawIter iter(this);
590
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000591#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000592 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700593 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000594 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000596
reedc83a2972015-07-16 07:40:45 -0700597#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
598 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700599 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700600 while (looper.next(type)) { \
601 SkDrawIter iter(this);
602
reed@google.com4e2b3d32011-04-07 14:18:59 +0000603#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000604
605////////////////////////////////////////////////////////////////////////////
606
msarettfbfa2582016-08-12 08:29:08 -0700607static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
608 if (bounds.isEmpty()) {
609 return SkRect::MakeEmpty();
610 }
611
612 // Expand bounds out by 1 in case we are anti-aliasing. We store the
613 // bounds as floats to enable a faster quick reject implementation.
614 SkRect dst;
615 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
616 return dst;
617}
618
mtkleinfeaadee2015-04-08 11:25:48 -0700619void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
620 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700621 fMCRec->reset(bounds);
622
623 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500624 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400625 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700626 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700627 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700628}
629
reedd9544982014-09-09 18:46:22 -0700630SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800631 if (device && device->forceConservativeRasterClip()) {
632 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
633 }
reed42b73eb2015-11-20 13:42:42 -0800634
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000635 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800636 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700637 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638
639 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500640 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500641 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700642 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643
reeda499f902015-05-01 09:34:31 -0700644 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
645 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400646 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700647
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649
halcanary96fcdcc2015-08-27 07:41:13 -0700650 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000651
reedf92c8662014-08-18 08:02:43 -0700652 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700653 // The root device and the canvas should always have the same pixel geometry
654 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800655 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700656 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500657
Mike Reedc42a1cd2017-02-14 14:25:14 -0500658 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700659 }
msarettfbfa2582016-08-12 08:29:08 -0700660
reedf92c8662014-08-18 08:02:43 -0700661 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662}
663
reed@google.comcde92112011-07-06 20:00:52 +0000664SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000665 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700666 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000667{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000668 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000669
halcanary96fcdcc2015-08-27 07:41:13 -0700670 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000671}
672
reed96a857e2015-01-25 10:33:58 -0800673SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000674 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800675 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000676{
677 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700678
Mike Reed566e53c2017-03-10 10:49:45 -0500679 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700680 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700681}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000682
reed78e27682014-11-19 08:04:34 -0800683SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700684 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700685 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700686{
687 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700688
Mike Reed566e53c2017-03-10 10:49:45 -0500689 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
690 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700691}
692
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000693SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000694 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700695 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000696{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700698
reedd9544982014-09-09 18:46:22 -0700699 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000700}
701
robertphillipsfcf78292015-06-19 11:49:52 -0700702SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
703 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700704 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700705{
706 inc_canvas();
707
708 this->init(device, flags);
709}
710
reed4a8126e2014-09-22 07:29:03 -0700711SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700712 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700713 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700714{
715 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700716
Hal Canary704cd322016-11-07 14:13:52 -0500717 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
718 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700719}
reed29c857d2014-09-21 10:25:07 -0700720
Mike Reed356f7c22017-01-10 11:58:39 -0500721SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
722 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700723 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
724 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500725 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700726{
727 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700728
Mike Reed356f7c22017-01-10 11:58:39 -0500729 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500730 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000731}
732
Mike Reed356f7c22017-01-10 11:58:39 -0500733SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
734
Matt Sarett31f99ce2017-04-11 08:46:01 -0400735#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
736SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
737 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
738 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
739 , fAllocator(nullptr)
740{
741 inc_canvas();
742
743 SkBitmap tmp(bitmap);
744 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
745 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
746 this->init(device.get(), kDefault_InitFlags);
747}
748#endif
749
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750SkCanvas::~SkCanvas() {
751 // free up the contents of our deque
752 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000753
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754 this->internalRestore(); // restore the last, since we're going away
755
halcanary385fe4d2015-08-26 13:07:48 -0700756 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000757
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758 dec_canvas();
759}
760
fmalita53d9f1c2016-01-25 06:23:54 -0800761#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762SkDrawFilter* SkCanvas::getDrawFilter() const {
763 return fMCRec->fFilter;
764}
765
766SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700767 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
769 return filter;
770}
fmalita77650002016-01-21 18:47:11 -0800771#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000773SkMetaData& SkCanvas::getMetaData() {
774 // metadata users are rare, so we lazily allocate it. If that changes we
775 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700776 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000777 fMetaData = new SkMetaData;
778 }
779 return *fMetaData;
780}
781
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782///////////////////////////////////////////////////////////////////////////////
783
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000784void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700785 this->onFlush();
786}
787
788void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000789 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000790 if (device) {
791 device->flush();
792 }
793}
794
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000795SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000796 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000797 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
798}
799
senorblancoafc7cce2016-02-02 18:44:15 -0800800SkIRect SkCanvas::getTopLayerBounds() const {
801 SkBaseDevice* d = this->getTopDevice();
802 if (!d) {
803 return SkIRect::MakeEmpty();
804 }
805 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
806}
807
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000808SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000810 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000811 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400812 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813}
814
Florin Malita0ed3b642017-01-13 16:56:38 +0000815SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400816 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000817}
818
reed96472de2014-12-10 09:53:42 -0800819bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000820 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000821 if (!device) {
822 return false;
823 }
mtkleinf0f14112014-12-12 08:46:25 -0800824
Matt Sarett03dd6d52017-01-23 12:15:09 -0500825 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000826}
827
Mike Reed12e946b2017-04-17 10:53:29 -0400828bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
829 return pm.addr() && this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y);
830}
831
832bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
833 SkPixmap pm;
834 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
835}
836
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000837bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400838 SkPixmap pm;
839 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700840 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000841 }
842 return false;
843}
844
Matt Sarett03dd6d52017-01-23 12:15:09 -0500845bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000846 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000847 SkBaseDevice* device = this->getDevice();
848 if (!device) {
849 return false;
850 }
851
Matt Sarett03dd6d52017-01-23 12:15:09 -0500852 // This check gives us an early out and prevents generation ID churn on the surface.
853 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
854 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
855 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
856 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000857 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000858
Matt Sarett03dd6d52017-01-23 12:15:09 -0500859 // Tell our owning surface to bump its generation ID.
860 const bool completeOverwrite =
861 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700862 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700863
Matt Sarett03dd6d52017-01-23 12:15:09 -0500864 // This can still fail, most notably in the case of a invalid color type or alpha type
865 // conversion. We could pull those checks into this function and avoid the unnecessary
866 // generation ID bump. But then we would be performing those checks twice, since they
867 // are also necessary at the bitmap/pixmap entry points.
868 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000869}
reed@google.com51df9e32010-12-23 19:29:18 +0000870
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871//////////////////////////////////////////////////////////////////////////////
872
reed2ff1fce2014-12-11 07:07:37 -0800873void SkCanvas::checkForDeferredSave() {
874 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800875 this->doSave();
876 }
877}
878
reedf0090cb2014-11-26 08:55:51 -0800879int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800880#ifdef SK_DEBUG
881 int count = 0;
882 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
883 for (;;) {
884 const MCRec* rec = (const MCRec*)iter.next();
885 if (!rec) {
886 break;
887 }
888 count += 1 + rec->fDeferredSaveCount;
889 }
890 SkASSERT(count == fSaveCount);
891#endif
892 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800893}
894
895int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800896 fSaveCount += 1;
897 fMCRec->fDeferredSaveCount += 1;
898 return this->getSaveCount() - 1; // return our prev value
899}
900
901void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800902 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700903
904 SkASSERT(fMCRec->fDeferredSaveCount > 0);
905 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800906 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800907}
908
909void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800910 if (fMCRec->fDeferredSaveCount > 0) {
911 SkASSERT(fSaveCount > 1);
912 fSaveCount -= 1;
913 fMCRec->fDeferredSaveCount -= 1;
914 } else {
915 // check for underflow
916 if (fMCStack.count() > 1) {
917 this->willRestore();
918 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700919 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800920 this->internalRestore();
921 this->didRestore();
922 }
reedf0090cb2014-11-26 08:55:51 -0800923 }
924}
925
926void SkCanvas::restoreToCount(int count) {
927 // sanity check
928 if (count < 1) {
929 count = 1;
930 }
mtkleinf0f14112014-12-12 08:46:25 -0800931
reedf0090cb2014-11-26 08:55:51 -0800932 int n = this->getSaveCount() - count;
933 for (int i = 0; i < n; ++i) {
934 this->restore();
935 }
936}
937
reed2ff1fce2014-12-11 07:07:37 -0800938void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700940 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000941 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000942
Mike Reedc42a1cd2017-02-14 14:25:14 -0500943 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944}
945
reed4960eee2015-12-18 07:09:18 -0800946bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800947 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000948}
949
reed4960eee2015-12-18 07:09:18 -0800950bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700951 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500952 SkIRect clipBounds = this->getDeviceClipBounds();
953 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000954 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000955 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000956
reed96e657d2015-03-10 17:30:07 -0700957 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
958
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000959 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700960 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800961 if (bounds && !imageFilter->canComputeFastBounds()) {
962 bounds = nullptr;
963 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000964 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000965 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700966 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000968
reed96e657d2015-03-10 17:30:07 -0700969 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970 r.roundOut(&ir);
971 // early exit if the layer's bounds are clipped out
972 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800973 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500974 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700975 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700976 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000977 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000978 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979 }
980 } else { // no user bounds, so just use the clip
981 ir = clipBounds;
982 }
reed180aec42015-03-11 10:39:04 -0700983 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984
reed4960eee2015-12-18 07:09:18 -0800985 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700986 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700987 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700988 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000989 }
990
991 if (intersection) {
992 *intersection = ir;
993 }
994 return true;
995}
996
reed4960eee2015-12-18 07:09:18 -0800997
reed4960eee2015-12-18 07:09:18 -0800998int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
999 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001000}
1001
reed70ee31b2015-12-10 13:44:45 -08001002int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001003 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1004}
1005
1006int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001007 SkTCopyOnFirstWrite<SaveLayerRec> rec(origRec);
reed4960eee2015-12-18 07:09:18 -08001008 if (gIgnoreSaveLayerBounds) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001009 rec.writable()->fBounds = nullptr;
reed4960eee2015-12-18 07:09:18 -08001010 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001011
1012 SaveLayerStrategy strategy = this->getSaveLayerStrategy(*rec);
reed4960eee2015-12-18 07:09:18 -08001013 fSaveCount += 1;
Florin Malita53f77bd2017-04-28 13:48:37 -04001014 this->internalSaveLayer(*rec, strategy);
reed4960eee2015-12-18 07:09:18 -08001015 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001016}
1017
reeda2217ef2016-07-20 06:04:34 -07001018void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001019 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001020 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001021 SkDraw draw;
1022 SkRasterClip rc;
1023 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1024 if (!dst->accessPixels(&draw.fDst)) {
1025 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001026 }
reeda2217ef2016-07-20 06:04:34 -07001027 draw.fMatrix = &SkMatrix::I();
1028 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001029
1030 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001031 if (filter) {
1032 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1033 }
reeda2217ef2016-07-20 06:04:34 -07001034
Mike Reedc42a1cd2017-02-14 14:25:14 -05001035 int x = src->getOrigin().x() - dstOrigin.x();
1036 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001037 auto special = src->snapSpecial();
1038 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001039 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -07001040 }
robertphillips7354a4b2015-12-16 05:08:27 -08001041}
reed70ee31b2015-12-10 13:44:45 -08001042
reed129ed1c2016-02-22 06:42:31 -08001043static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1044 const SkPaint* paint) {
1045 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1046 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001047 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001048 const bool hasImageFilter = paint && paint->getImageFilter();
1049
1050 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1051 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1052 // force to L32
1053 return SkImageInfo::MakeN32(w, h, alphaType);
1054 } else {
1055 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001056 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001057 }
1058}
1059
reed4960eee2015-12-18 07:09:18 -08001060void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1061 const SkRect* bounds = rec.fBounds;
1062 const SkPaint* paint = rec.fPaint;
1063 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1064
reed8c30a812016-04-20 16:36:51 -07001065 SkLazyPaint lazyP;
1066 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1067 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001068 SkMatrix remainder;
1069 SkSize scale;
1070 /*
1071 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1072 * but they do handle scaling. To accommodate this, we do the following:
1073 *
1074 * 1. Stash off the current CTM
1075 * 2. Decompose the CTM into SCALE and REMAINDER
1076 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1077 * contains the REMAINDER
1078 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1079 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1080 * of the original imagefilter, and draw that (via drawSprite)
1081 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1082 *
1083 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1084 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1085 */
reed96a04f32016-04-25 09:25:15 -07001086 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001087 stashedMatrix.decomposeScale(&scale, &remainder))
1088 {
1089 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1090 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1091 SkPaint* p = lazyP.set(*paint);
1092 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1093 SkFilterQuality::kLow_SkFilterQuality,
1094 sk_ref_sp(imageFilter)));
1095 imageFilter = p->getImageFilter();
1096 paint = p;
1097 }
reed8c30a812016-04-20 16:36:51 -07001098
junov@chromium.orga907ac32012-02-24 21:54:07 +00001099 // do this before we create the layer. We don't call the public save() since
1100 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001101 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001102
junov@chromium.orga907ac32012-02-24 21:54:07 +00001103 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001104 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001105 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106 }
1107
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001108 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1109 // the clipRectBounds() call above?
1110 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001111 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001112 }
1113
reed4960eee2015-12-18 07:09:18 -08001114 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001115 SkPixelGeometry geo = fProps.pixelGeometry();
1116 if (paint) {
reed76033be2015-03-14 10:54:31 -07001117 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001118 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001119 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001120 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001121 }
1122 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001123
robertphillips5139e502016-07-19 05:10:40 -07001124 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001125 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001126 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001127 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001128 }
reedb2db8982014-11-13 12:41:02 -08001129
robertphillips5139e502016-07-19 05:10:40 -07001130 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001131 paint);
1132
Hal Canary704cd322016-11-07 14:13:52 -05001133 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001134 {
reed70ee31b2015-12-10 13:44:45 -08001135 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001136 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001137 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001138 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001139 preserveLCDText,
1140 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001141 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1142 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001143 return;
reed61f501f2015-04-29 08:34:00 -07001144 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001145 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001146 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147
Mike Reedb43a3e02017-02-11 10:18:58 -05001148 // only have a "next" if this new layer doesn't affect the clip (rare)
1149 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001150 fMCRec->fLayer = layer;
1151 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001152
Mike Reedc61abee2017-02-28 17:45:27 -05001153 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001154 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001155 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001156 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001157
Mike Reedc42a1cd2017-02-14 14:25:14 -05001158 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1159
1160 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1161 if (layer->fNext) {
1162 // need to punch a hole in the previous device, so we don't draw there, given that
1163 // the new top-layer will allow drawing to happen "below" it.
1164 SkRegion hole(ir);
1165 do {
1166 layer = layer->fNext;
1167 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1168 } while (layer->fNext);
1169 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170}
1171
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001172int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001173 if (0xFF == alpha) {
1174 return this->saveLayer(bounds, nullptr);
1175 } else {
1176 SkPaint tmpPaint;
1177 tmpPaint.setAlpha(alpha);
1178 return this->saveLayer(bounds, &tmpPaint);
1179 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001180}
1181
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182void SkCanvas::internalRestore() {
1183 SkASSERT(fMCStack.count() != 0);
1184
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001185 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001186 DeviceCM* layer = fMCRec->fLayer; // may be null
1187 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001188 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189
1190 // now do the normal restore()
1191 fMCRec->~MCRec(); // balanced in save()
1192 fMCStack.pop_back();
1193 fMCRec = (MCRec*)fMCStack.back();
1194
Mike Reedc42a1cd2017-02-14 14:25:14 -05001195 if (fMCRec) {
1196 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1197 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001198
reed@android.com8a1c16f2008-12-17 15:59:43 +00001199 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1200 since if we're being recorded, we don't want to record this (the
1201 recorder will have already recorded the restore).
1202 */
bsalomon49f085d2014-09-05 13:34:00 -07001203 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001204 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001205 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001206 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001207 layer->fPaint.get(),
1208 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001209 // restore what we smashed in internalSaveLayer
1210 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001211 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001212 delete layer;
reedb679ca82015-04-07 04:40:48 -07001213 } else {
1214 // we're at the root
reeda499f902015-05-01 09:34:31 -07001215 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001216 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001217 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001219 }
msarettfbfa2582016-08-12 08:29:08 -07001220
1221 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001222 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001223 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1224 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001225}
1226
reede8f30622016-03-23 18:59:25 -07001227sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001228 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001229 props = &fProps;
1230 }
1231 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001232}
1233
reede8f30622016-03-23 18:59:25 -07001234sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001235 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001236 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001237}
1238
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001239SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001240 return this->onImageInfo();
1241}
1242
1243SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001244 SkBaseDevice* dev = this->getDevice();
1245 if (dev) {
1246 return dev->imageInfo();
1247 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001248 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001249 }
1250}
1251
brianosman898235c2016-04-06 07:38:23 -07001252bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001253 return this->onGetProps(props);
1254}
1255
1256bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001257 SkBaseDevice* dev = this->getDevice();
1258 if (dev) {
1259 if (props) {
1260 *props = fProps;
1261 }
1262 return true;
1263 } else {
1264 return false;
1265 }
1266}
1267
reed6ceeebd2016-03-09 14:26:26 -08001268bool SkCanvas::peekPixels(SkPixmap* pmap) {
1269 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001270}
1271
reed884e97c2015-05-26 11:31:54 -07001272bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001273 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001274 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001275}
1276
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001277void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001278 SkPixmap pmap;
1279 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001280 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001281 }
1282 if (info) {
1283 *info = pmap.info();
1284 }
1285 if (rowBytes) {
1286 *rowBytes = pmap.rowBytes();
1287 }
1288 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001289 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001290 }
reed884e97c2015-05-26 11:31:54 -07001291 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001292}
1293
reed884e97c2015-05-26 11:31:54 -07001294bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001295 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001296 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001297}
1298
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300
Florin Malita53f77bd2017-04-28 13:48:37 -04001301void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1302 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001304 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 paint = &tmp;
1306 }
reed@google.com4b226022011-01-11 18:32:13 +00001307
reed@google.com8926b162012-03-23 15:36:36 +00001308 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001309
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001311 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001312 paint = &looper.paint();
1313 SkImageFilter* filter = paint->getImageFilter();
1314 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001315 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001316 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1317 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001318 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1319 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001320 }
reed@google.com76dd2772012-01-05 21:15:07 +00001321 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001322 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001323 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324 }
reeda2217ef2016-07-20 06:04:34 -07001325
reed@google.com4e2b3d32011-04-07 14:18:59 +00001326 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327}
1328
reed32704672015-12-16 08:27:10 -08001329/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001330
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001331void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001332 if (dx || dy) {
1333 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001334 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001335
reedfe69b502016-09-12 06:31:48 -07001336 // Translate shouldn't affect the is-scale-translateness of the matrix.
1337 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001338
Mike Reedc42a1cd2017-02-14 14:25:14 -05001339 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001340
reedfe69b502016-09-12 06:31:48 -07001341 this->didTranslate(dx,dy);
1342 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343}
1344
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001345void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001346 SkMatrix m;
1347 m.setScale(sx, sy);
1348 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001349}
1350
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001351void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001352 SkMatrix m;
1353 m.setRotate(degrees);
1354 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001355}
1356
bungeman7438bfc2016-07-12 15:01:19 -07001357void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1358 SkMatrix m;
1359 m.setRotate(degrees, px, py);
1360 this->concat(m);
1361}
1362
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001363void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001364 SkMatrix m;
1365 m.setSkew(sx, sy);
1366 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001367}
1368
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001369void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001370 if (matrix.isIdentity()) {
1371 return;
1372 }
1373
reed2ff1fce2014-12-11 07:07:37 -08001374 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001375 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001376 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001377
Mike Reed7627fa52017-02-08 10:07:53 -05001378 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001379
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001380 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001381}
1382
reed8c30a812016-04-20 16:36:51 -07001383void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001384 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001385 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001386
Mike Reedc42a1cd2017-02-14 14:25:14 -05001387 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001388}
1389
1390void SkCanvas::setMatrix(const SkMatrix& matrix) {
1391 this->checkForDeferredSave();
1392 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001393 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001394}
1395
reed@android.com8a1c16f2008-12-17 15:59:43 +00001396void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001397 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001398}
1399
1400//////////////////////////////////////////////////////////////////////////////
1401
Mike Reedc1f77742016-12-09 09:00:50 -05001402void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001403 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001404 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1405 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001406}
1407
Mike Reedc1f77742016-12-09 09:00:50 -05001408void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001409 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001410
Mike Reed7627fa52017-02-08 10:07:53 -05001411 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001412
reedc64eff52015-11-21 12:39:45 -08001413 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001414 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1415 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001416 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001417}
1418
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001419void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1420 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001421 if (fClipRestrictionRect.isEmpty()) {
1422 // we notify the device, but we *dont* resolve deferred saves (since we're just
1423 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001424 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001425 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001426 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001427 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001428 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001429 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001430 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1431 }
1432}
1433
Mike Reedc1f77742016-12-09 09:00:50 -05001434void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001435 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001436 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001437 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001438 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1439 } else {
1440 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001441 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001442}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001443
Mike Reedc1f77742016-12-09 09:00:50 -05001444void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001445 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001446
Brian Salomona3b45d42016-10-03 11:36:16 -04001447 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001448
Mike Reed7627fa52017-02-08 10:07:53 -05001449 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001450
Brian Salomona3b45d42016-10-03 11:36:16 -04001451 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1452 isAA);
1453 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001454}
1455
Mike Reedc1f77742016-12-09 09:00:50 -05001456void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001457 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001458 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001459
1460 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1461 SkRect r;
1462 if (path.isRect(&r)) {
1463 this->onClipRect(r, op, edgeStyle);
1464 return;
1465 }
1466 SkRRect rrect;
1467 if (path.isOval(&r)) {
1468 rrect.setOval(r);
1469 this->onClipRRect(rrect, op, edgeStyle);
1470 return;
1471 }
1472 if (path.isRRect(&rrect)) {
1473 this->onClipRRect(rrect, op, edgeStyle);
1474 return;
1475 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001476 }
robertphillips39f05382015-11-24 09:30:12 -08001477
1478 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001479}
1480
Mike Reedc1f77742016-12-09 09:00:50 -05001481void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001482 AutoValidateClip avc(this);
1483
Brian Salomona3b45d42016-10-03 11:36:16 -04001484 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001485
Mike Reed7627fa52017-02-08 10:07:53 -05001486 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001487
Brian Salomona3b45d42016-10-03 11:36:16 -04001488 const SkPath* rasterClipPath = &path;
1489 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001490 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1491 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001492 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001493}
1494
Mike Reedc1f77742016-12-09 09:00:50 -05001495void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001496 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001497 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001498}
1499
Mike Reedc1f77742016-12-09 09:00:50 -05001500void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001501 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001502
reed@google.com5c3d1472011-02-22 19:12:23 +00001503 AutoValidateClip avc(this);
1504
reed73603f32016-09-20 08:42:38 -07001505 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001506 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001507}
1508
reed@google.com819c9212011-02-23 18:56:55 +00001509#ifdef SK_DEBUG
1510void SkCanvas::validateClip() const {
1511 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001512 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001513 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001514 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001515 return;
1516 }
reed@google.com819c9212011-02-23 18:56:55 +00001517}
1518#endif
1519
Mike Reeda1361362017-03-07 09:37:29 -05001520bool SkCanvas::androidFramework_isClipAA() const {
1521 bool containsAA = false;
1522
1523 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1524
1525 return containsAA;
1526}
1527
1528class RgnAccumulator {
1529 SkRegion* fRgn;
1530public:
1531 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1532 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1533 SkIPoint origin = device->getOrigin();
1534 if (origin.x() | origin.y()) {
1535 rgn->translate(origin.x(), origin.y());
1536 }
1537 fRgn->op(*rgn, SkRegion::kUnion_Op);
1538 }
1539};
1540
1541void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1542 RgnAccumulator accum(rgn);
1543 SkRegion tmp;
1544
1545 rgn->setEmpty();
1546 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001547}
1548
reed@google.com5c3d1472011-02-22 19:12:23 +00001549///////////////////////////////////////////////////////////////////////////////
1550
reed@google.com754de5f2014-02-24 19:38:20 +00001551bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001552 return fMCRec->fRasterClip.isEmpty();
1553
1554 // TODO: should we only use the conservative answer in a recording canvas?
1555#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001556 SkBaseDevice* dev = this->getTopDevice();
1557 // if no device we return true
1558 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001559#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001560}
1561
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001562bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001563 SkBaseDevice* dev = this->getTopDevice();
1564 // if no device we return false
1565 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001566}
1567
msarettfbfa2582016-08-12 08:29:08 -07001568static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1569#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1570 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1571 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1572 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1573 return 0xF != _mm_movemask_ps(mask);
1574#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1575 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1576 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1577 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1578 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1579#else
1580 SkRect devRectAsRect;
1581 SkRect devClipAsRect;
1582 devRect.store(&devRectAsRect.fLeft);
1583 devClip.store(&devClipAsRect.fLeft);
1584 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1585#endif
1586}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001587
msarettfbfa2582016-08-12 08:29:08 -07001588// It's important for this function to not be inlined. Otherwise the compiler will share code
1589// between the fast path and the slow path, resulting in two slow paths.
1590static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1591 const SkMatrix& matrix) {
1592 SkRect deviceRect;
1593 matrix.mapRect(&deviceRect, src);
1594 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1595}
1596
1597bool SkCanvas::quickReject(const SkRect& src) const {
1598#ifdef SK_DEBUG
1599 // Verify that fDeviceClipBounds are set properly.
1600 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001601 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001602 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001603 } else {
msarettfbfa2582016-08-12 08:29:08 -07001604 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001605 }
msarettfbfa2582016-08-12 08:29:08 -07001606
msarett9637ea92016-08-18 14:03:30 -07001607 // Verify that fIsScaleTranslate is set properly.
1608 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001609#endif
1610
msarett9637ea92016-08-18 14:03:30 -07001611 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001612 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1613 }
1614
1615 // We inline the implementation of mapScaleTranslate() for the fast path.
1616 float sx = fMCRec->fMatrix.getScaleX();
1617 float sy = fMCRec->fMatrix.getScaleY();
1618 float tx = fMCRec->fMatrix.getTranslateX();
1619 float ty = fMCRec->fMatrix.getTranslateY();
1620 Sk4f scale(sx, sy, sx, sy);
1621 Sk4f trans(tx, ty, tx, ty);
1622
1623 // Apply matrix.
1624 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1625
1626 // Make sure left < right, top < bottom.
1627 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1628 Sk4f min = Sk4f::Min(ltrb, rblt);
1629 Sk4f max = Sk4f::Max(ltrb, rblt);
1630 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1631 // ARM this sequence generates the fastest (a single instruction).
1632 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1633
1634 // Check if the device rect is NaN or outside the clip.
1635 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001636}
1637
reed@google.com3b3e8952012-08-16 20:53:31 +00001638bool SkCanvas::quickReject(const SkPath& path) const {
1639 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001640}
1641
Mike Reed42e8c532017-01-23 14:09:13 -05001642SkRect SkCanvas::onGetLocalClipBounds() const {
1643 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001644 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001645 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001646 }
1647
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001648 SkMatrix inverse;
1649 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001650 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001651 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001652 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001653
Mike Reed42e8c532017-01-23 14:09:13 -05001654 SkRect bounds;
1655 SkRect r;
1656 // adjust it outwards in case we are antialiasing
1657 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001658
Mike Reed42e8c532017-01-23 14:09:13 -05001659 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1660 ibounds.fRight + inset, ibounds.fBottom + inset);
1661 inverse.mapRect(&bounds, r);
1662 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001663}
1664
Mike Reed42e8c532017-01-23 14:09:13 -05001665SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001666 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001667}
1668
reed@android.com8a1c16f2008-12-17 15:59:43 +00001669const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001670 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001671}
1672
Brian Osman11052242016-10-27 14:47:55 -04001673GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001674 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001675 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001676}
1677
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001678GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001679 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001680 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001681}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001682
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001683void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1684 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001685 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001686 if (outer.isEmpty()) {
1687 return;
1688 }
1689 if (inner.isEmpty()) {
1690 this->drawRRect(outer, paint);
1691 return;
1692 }
1693
1694 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001695 // be able to return ...
1696 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001697 //
1698 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001699 if (!outer.getBounds().contains(inner.getBounds())) {
1700 return;
1701 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001702
1703 this->onDrawDRRect(outer, inner, paint);
1704}
1705
reed41af9662015-01-05 07:49:08 -08001706// These need to stop being virtual -- clients need to override the onDraw... versions
1707
1708void SkCanvas::drawPaint(const SkPaint& paint) {
1709 this->onDrawPaint(paint);
1710}
1711
1712void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1713 this->onDrawRect(r, paint);
1714}
1715
msarettdca352e2016-08-26 06:37:45 -07001716void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1717 if (region.isEmpty()) {
1718 return;
1719 }
1720
1721 if (region.isRect()) {
1722 return this->drawIRect(region.getBounds(), paint);
1723 }
1724
1725 this->onDrawRegion(region, paint);
1726}
1727
reed41af9662015-01-05 07:49:08 -08001728void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1729 this->onDrawOval(r, paint);
1730}
1731
1732void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1733 this->onDrawRRect(rrect, paint);
1734}
1735
1736void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1737 this->onDrawPoints(mode, count, pts, paint);
1738}
1739
Mike Reede88a1cb2017-03-17 09:50:46 -04001740void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1741 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001742 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001743 this->onDrawVerticesObject(vertices.get(), mode, paint);
1744}
1745
1746void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1747 RETURN_ON_NULL(vertices);
1748 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001749}
1750
1751void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1752 this->onDrawPath(path, paint);
1753}
1754
reeda85d4d02015-05-06 12:56:48 -07001755void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001756 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001757 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001758}
1759
reede47829b2015-08-06 10:02:53 -07001760void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1761 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001762 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001763 if (dst.isEmpty() || src.isEmpty()) {
1764 return;
1765 }
1766 this->onDrawImageRect(image, &src, dst, paint, constraint);
1767}
reed41af9662015-01-05 07:49:08 -08001768
reed84984ef2015-07-17 07:09:43 -07001769void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1770 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001771 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001772 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001773}
1774
reede47829b2015-08-06 10:02:53 -07001775void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1776 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001777 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001778 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1779 constraint);
1780}
reede47829b2015-08-06 10:02:53 -07001781
reed4c21dc52015-06-25 12:32:03 -07001782void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1783 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001784 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001785 if (dst.isEmpty()) {
1786 return;
1787 }
msarett552bca92016-08-03 06:53:26 -07001788 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1789 this->onDrawImageNine(image, center, dst, paint);
1790 } else {
reede47829b2015-08-06 10:02:53 -07001791 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001792 }
reed4c21dc52015-06-25 12:32:03 -07001793}
1794
msarett16882062016-08-16 09:31:08 -07001795void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1796 const SkPaint* paint) {
1797 RETURN_ON_NULL(image);
1798 if (dst.isEmpty()) {
1799 return;
1800 }
msarett71df2d72016-09-30 12:41:42 -07001801
1802 SkIRect bounds;
1803 Lattice latticePlusBounds = lattice;
1804 if (!latticePlusBounds.fBounds) {
1805 bounds = SkIRect::MakeWH(image->width(), image->height());
1806 latticePlusBounds.fBounds = &bounds;
1807 }
1808
1809 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1810 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001811 } else {
1812 this->drawImageRect(image, dst, paint);
1813 }
1814}
1815
reed41af9662015-01-05 07:49:08 -08001816void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001817 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001818 return;
1819 }
reed41af9662015-01-05 07:49:08 -08001820 this->onDrawBitmap(bitmap, dx, dy, paint);
1821}
1822
reede47829b2015-08-06 10:02:53 -07001823void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001824 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001825 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001826 return;
1827 }
reede47829b2015-08-06 10:02:53 -07001828 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001829}
1830
reed84984ef2015-07-17 07:09:43 -07001831void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1832 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001833 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001834}
1835
reede47829b2015-08-06 10:02:53 -07001836void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1837 SrcRectConstraint constraint) {
1838 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1839 constraint);
1840}
reede47829b2015-08-06 10:02:53 -07001841
reed41af9662015-01-05 07:49:08 -08001842void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1843 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001844 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001845 return;
1846 }
msarett552bca92016-08-03 06:53:26 -07001847 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1848 this->onDrawBitmapNine(bitmap, center, dst, paint);
1849 } else {
reeda5517e22015-07-14 10:54:12 -07001850 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001851 }
reed41af9662015-01-05 07:49:08 -08001852}
1853
msarettc573a402016-08-02 08:05:56 -07001854void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1855 const SkPaint* paint) {
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) {
reede3b38ce2016-01-08 09:18:44 -08001877 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001878 if (count <= 0) {
1879 return;
1880 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001881 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001882 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001883 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001884}
1885
reedf70b5312016-03-04 16:36:20 -08001886void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1887 if (key) {
1888 this->onDrawAnnotation(rect, key, value);
1889 }
1890}
1891
reede47829b2015-08-06 10:02:53 -07001892void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1893 const SkPaint* paint, SrcRectConstraint constraint) {
1894 if (src) {
1895 this->drawImageRect(image, *src, dst, paint, constraint);
1896 } else {
1897 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1898 dst, paint, constraint);
1899 }
1900}
1901void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1902 const SkPaint* paint, SrcRectConstraint constraint) {
1903 if (src) {
1904 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1905 } else {
1906 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1907 dst, paint, constraint);
1908 }
1909}
1910
reed@android.com8a1c16f2008-12-17 15:59:43 +00001911//////////////////////////////////////////////////////////////////////////////
1912// These are the virtual drawing methods
1913//////////////////////////////////////////////////////////////////////////////
1914
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001915void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001916 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001917 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1918 }
1919}
1920
reed41af9662015-01-05 07:49:08 -08001921void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001922 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001923 this->internalDrawPaint(paint);
1924}
1925
1926void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001927 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001928
1929 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001930 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001931 }
1932
reed@google.com4e2b3d32011-04-07 14:18:59 +00001933 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001934}
1935
reed41af9662015-01-05 07:49:08 -08001936void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1937 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001938 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001939 if ((long)count <= 0) {
1940 return;
1941 }
1942
Mike Reed822128b2017-02-28 16:41:03 -05001943 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001944 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001945 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001946 // special-case 2 points (common for drawing a single line)
1947 if (2 == count) {
1948 r.set(pts[0], pts[1]);
1949 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001950 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001951 }
Mike Reed822128b2017-02-28 16:41:03 -05001952 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001953 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1954 return;
1955 }
1956 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001957 }
reed@google.coma584aed2012-05-16 14:06:02 +00001958
halcanary96fcdcc2015-08-27 07:41:13 -07001959 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001960
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001961 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001962
reed@android.com8a1c16f2008-12-17 15:59:43 +00001963 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001964 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001965 }
reed@google.com4b226022011-01-11 18:32:13 +00001966
reed@google.com4e2b3d32011-04-07 14:18:59 +00001967 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001968}
1969
reed4a167172016-08-18 17:15:25 -07001970static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1971 return ((intptr_t)paint.getImageFilter() |
1972#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1973 (intptr_t)canvas->getDrawFilter() |
1974#endif
1975 (intptr_t)paint.getLooper() ) != 0;
1976}
1977
reed41af9662015-01-05 07:49:08 -08001978void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001979 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001980 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001981 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1982 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1983 SkRect tmp(r);
1984 tmp.sort();
1985
Mike Reed822128b2017-02-28 16:41:03 -05001986 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001987 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
1988 return;
1989 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001990 }
reed@google.com4b226022011-01-11 18:32:13 +00001991
reed4a167172016-08-18 17:15:25 -07001992 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05001993 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001994
reed4a167172016-08-18 17:15:25 -07001995 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001996 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07001997 }
1998
1999 LOOPER_END
2000 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002001 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002002 SkDrawIter iter(this);
2003 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002004 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002005 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002006 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002007}
2008
msarett44df6512016-08-25 13:54:30 -07002009void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002010 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002011 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002012 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002013 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2014 return;
2015 }
msarett44df6512016-08-25 13:54:30 -07002016 }
2017
Mike Reed822128b2017-02-28 16:41:03 -05002018 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002019
2020 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002021 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002022 }
2023
2024 LOOPER_END
2025}
2026
reed41af9662015-01-05 07:49:08 -08002027void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002028 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002029 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002030 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002031 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2032 return;
2033 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002034 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002035
Mike Reed822128b2017-02-28 16:41:03 -05002036 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002037
2038 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002039 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002040 }
2041
2042 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002043}
2044
bsalomonac3aa242016-08-19 11:25:19 -07002045void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2046 SkScalar sweepAngle, bool useCenter,
2047 const SkPaint& paint) {
2048 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002049 if (paint.canComputeFastBounds()) {
2050 SkRect storage;
2051 // Note we're using the entire oval as the bounds.
2052 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2053 return;
2054 }
bsalomonac3aa242016-08-19 11:25:19 -07002055 }
2056
Mike Reed822128b2017-02-28 16:41:03 -05002057 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002058
2059 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002060 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002061 }
2062
2063 LOOPER_END
2064}
2065
reed41af9662015-01-05 07:49:08 -08002066void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002067 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002068 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002069 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002070 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2071 return;
2072 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002073 }
2074
2075 if (rrect.isRect()) {
2076 // call the non-virtual version
2077 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002078 return;
2079 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002080 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002081 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2082 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002083 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002084
Mike Reed822128b2017-02-28 16:41:03 -05002085 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002086
2087 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002088 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002089 }
2090
2091 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002092}
2093
Mike Reed822128b2017-02-28 16:41:03 -05002094void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002095 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002096 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002097 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2098 return;
2099 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002100 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002101
Mike Reed822128b2017-02-28 16:41:03 -05002102 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002103
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002104 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002105 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002106 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002107
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002108 LOOPER_END
2109}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002110
reed41af9662015-01-05 07:49:08 -08002111void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002112 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002113 if (!path.isFinite()) {
2114 return;
2115 }
2116
Mike Reed822128b2017-02-28 16:41:03 -05002117 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002118 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002119 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002120 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2121 return;
2122 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002123 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002124
Mike Reed822128b2017-02-28 16:41:03 -05002125 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002126 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002127 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002128 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002129 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002130 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002131
Mike Reed822128b2017-02-28 16:41:03 -05002132 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002133
2134 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002135 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002136 }
2137
reed@google.com4e2b3d32011-04-07 14:18:59 +00002138 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002139}
2140
reed262a71b2015-12-05 13:07:27 -08002141bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002142 if (!paint.getImageFilter()) {
2143 return false;
2144 }
2145
2146 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002147 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002148 return false;
2149 }
2150
2151 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2152 // Once we can filter and the filter will return a result larger than itself, we should be
2153 // able to remove this constraint.
2154 // skbug.com/4526
2155 //
2156 SkPoint pt;
2157 ctm.mapXY(x, y, &pt);
2158 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2159 return ir.contains(fMCRec->fRasterClip.getBounds());
2160}
2161
reeda85d4d02015-05-06 12:56:48 -07002162void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002163 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002164 SkRect bounds = SkRect::MakeXYWH(x, y,
2165 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002166 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002167 SkRect tmp = bounds;
2168 if (paint) {
2169 paint->computeFastBounds(tmp, &tmp);
2170 }
2171 if (this->quickReject(tmp)) {
2172 return;
2173 }
reeda85d4d02015-05-06 12:56:48 -07002174 }
halcanary9d524f22016-03-29 09:03:52 -07002175
reeda85d4d02015-05-06 12:56:48 -07002176 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002177 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002178 paint = lazy.init();
2179 }
reed262a71b2015-12-05 13:07:27 -08002180
reeda2217ef2016-07-20 06:04:34 -07002181 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002182 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2183 *paint);
2184 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002185 special = this->getDevice()->makeSpecial(image);
2186 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002187 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002188 }
2189 }
2190
reed262a71b2015-12-05 13:07:27 -08002191 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2192
reeda85d4d02015-05-06 12:56:48 -07002193 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002194 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002195 if (special) {
2196 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002197 iter.fDevice->ctm().mapXY(x, y, &pt);
2198 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002199 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002200 SkScalarRoundToInt(pt.fY), pnt,
2201 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002202 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002203 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002204 }
reeda85d4d02015-05-06 12:56:48 -07002205 }
halcanary9d524f22016-03-29 09:03:52 -07002206
reeda85d4d02015-05-06 12:56:48 -07002207 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002208}
2209
reed41af9662015-01-05 07:49:08 -08002210void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002211 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002212 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002213 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002214 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002215 if (paint) {
2216 paint->computeFastBounds(dst, &storage);
2217 }
2218 if (this->quickReject(storage)) {
2219 return;
2220 }
reeda85d4d02015-05-06 12:56:48 -07002221 }
2222 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002223 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002224 paint = lazy.init();
2225 }
halcanary9d524f22016-03-29 09:03:52 -07002226
senorblancoc41e7e12015-12-07 12:51:30 -08002227 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002228 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002229
reeda85d4d02015-05-06 12:56:48 -07002230 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002231 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002232 }
halcanary9d524f22016-03-29 09:03:52 -07002233
reeda85d4d02015-05-06 12:56:48 -07002234 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002235}
2236
reed41af9662015-01-05 07:49:08 -08002237void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002238 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002239 SkDEBUGCODE(bitmap.validate();)
2240
reed33366972015-10-08 09:22:02 -07002241 if (bitmap.drawsNothing()) {
2242 return;
2243 }
2244
2245 SkLazyPaint lazy;
2246 if (nullptr == paint) {
2247 paint = lazy.init();
2248 }
2249
Mike Reed822128b2017-02-28 16:41:03 -05002250 SkRect bounds;
2251 bitmap.getBounds(&bounds);
2252 bounds.offset(x, y);
2253 bool canFastBounds = paint->canComputeFastBounds();
2254 if (canFastBounds) {
2255 SkRect storage;
2256 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002257 return;
2258 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002259 }
reed@google.com4b226022011-01-11 18:32:13 +00002260
reeda2217ef2016-07-20 06:04:34 -07002261 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002262 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2263 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002264 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002265 special = this->getDevice()->makeSpecial(bitmap);
2266 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002267 drawAsSprite = false;
2268 }
2269 }
2270
Mike Reed822128b2017-02-28 16:41:03 -05002271 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2272
2273 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002274
2275 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002276 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002277 if (special) {
reed262a71b2015-12-05 13:07:27 -08002278 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002279 iter.fDevice->ctm().mapXY(x, y, &pt);
2280 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002281 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002282 SkScalarRoundToInt(pt.fY), pnt,
2283 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002284 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002285 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002286 }
reed33366972015-10-08 09:22:02 -07002287 }
msarettfbfa2582016-08-12 08:29:08 -07002288
reed33366972015-10-08 09:22:02 -07002289 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290}
2291
reed@google.com9987ec32011-09-07 11:57:52 +00002292// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002293void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002294 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002295 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002296 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002297 return;
2298 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002299
halcanary96fcdcc2015-08-27 07:41:13 -07002300 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002301 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002302 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2303 return;
2304 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305 }
reed@google.com3d608122011-11-21 15:16:16 +00002306
reed@google.com33535f32012-09-25 15:37:50 +00002307 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002308 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002309 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002310 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002311
senorblancoc41e7e12015-12-07 12:51:30 -08002312 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002313 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002314
reed@google.com33535f32012-09-25 15:37:50 +00002315 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002316 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002317 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002318
reed@google.com33535f32012-09-25 15:37:50 +00002319 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002320}
2321
reed41af9662015-01-05 07:49:08 -08002322void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002323 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002324 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002325 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002326 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002327}
2328
reed4c21dc52015-06-25 12:32:03 -07002329void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2330 const SkPaint* paint) {
2331 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002332
halcanary96fcdcc2015-08-27 07:41:13 -07002333 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002334 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002335 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2336 return;
2337 }
reed@google.com3d608122011-11-21 15:16:16 +00002338 }
halcanary9d524f22016-03-29 09:03:52 -07002339
reed4c21dc52015-06-25 12:32:03 -07002340 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002341 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002342 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002343 }
halcanary9d524f22016-03-29 09:03:52 -07002344
senorblancoc41e7e12015-12-07 12:51:30 -08002345 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002346
reed4c21dc52015-06-25 12:32:03 -07002347 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002348 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002349 }
halcanary9d524f22016-03-29 09:03:52 -07002350
reed4c21dc52015-06-25 12:32:03 -07002351 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002352}
2353
reed41af9662015-01-05 07:49:08 -08002354void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2355 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002356 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002357 SkDEBUGCODE(bitmap.validate();)
2358
halcanary96fcdcc2015-08-27 07:41:13 -07002359 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002360 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002361 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2362 return;
2363 }
reed4c21dc52015-06-25 12:32:03 -07002364 }
halcanary9d524f22016-03-29 09:03:52 -07002365
reed4c21dc52015-06-25 12:32:03 -07002366 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002367 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002368 paint = lazy.init();
2369 }
halcanary9d524f22016-03-29 09:03:52 -07002370
senorblancoc41e7e12015-12-07 12:51:30 -08002371 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002372
reed4c21dc52015-06-25 12:32:03 -07002373 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002374 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002375 }
halcanary9d524f22016-03-29 09:03:52 -07002376
reed4c21dc52015-06-25 12:32:03 -07002377 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002378}
2379
msarett16882062016-08-16 09:31:08 -07002380void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2381 const SkPaint* paint) {
2382 if (nullptr == paint || paint->canComputeFastBounds()) {
2383 SkRect storage;
2384 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2385 return;
2386 }
2387 }
2388
2389 SkLazyPaint lazy;
2390 if (nullptr == paint) {
2391 paint = lazy.init();
2392 }
2393
2394 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2395
2396 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002397 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002398 }
2399
2400 LOOPER_END
2401}
2402
2403void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2404 const SkRect& dst, const SkPaint* paint) {
2405 if (nullptr == paint || paint->canComputeFastBounds()) {
2406 SkRect storage;
2407 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2408 return;
2409 }
2410 }
2411
2412 SkLazyPaint lazy;
2413 if (nullptr == paint) {
2414 paint = lazy.init();
2415 }
2416
2417 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2418
2419 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002420 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002421 }
2422
2423 LOOPER_END
2424}
2425
reed@google.comf67e4cf2011-03-15 20:56:58 +00002426class SkDeviceFilteredPaint {
2427public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002428 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002429 uint32_t filteredFlags = device->filterTextFlags(paint);
2430 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002431 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002432 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002433 fPaint = newPaint;
2434 } else {
2435 fPaint = &paint;
2436 }
2437 }
2438
reed@google.comf67e4cf2011-03-15 20:56:58 +00002439 const SkPaint& paint() const { return *fPaint; }
2440
2441private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002442 const SkPaint* fPaint;
2443 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002444};
2445
reed@google.come0d9ce82014-04-23 04:00:17 +00002446void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2447 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002448 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002449
2450 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002451 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002452 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002453 }
2454
reed@google.com4e2b3d32011-04-07 14:18:59 +00002455 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002456}
2457
reed@google.come0d9ce82014-04-23 04:00:17 +00002458void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2459 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002460 SkPoint textOffset = SkPoint::Make(0, 0);
2461
halcanary96fcdcc2015-08-27 07:41:13 -07002462 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002463
reed@android.com8a1c16f2008-12-17 15:59:43 +00002464 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002465 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002466 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002467 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002468 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002469
reed@google.com4e2b3d32011-04-07 14:18:59 +00002470 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002471}
2472
reed@google.come0d9ce82014-04-23 04:00:17 +00002473void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2474 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002475
2476 SkPoint textOffset = SkPoint::Make(0, constY);
2477
halcanary96fcdcc2015-08-27 07:41:13 -07002478 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002479
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002481 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002482 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002483 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002485
reed@google.com4e2b3d32011-04-07 14:18:59 +00002486 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002487}
2488
reed@google.come0d9ce82014-04-23 04:00:17 +00002489void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2490 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002491 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002492
reed@android.com8a1c16f2008-12-17 15:59:43 +00002493 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002494 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002495 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002497
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002498 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002499}
2500
reed45561a02016-07-07 12:47:17 -07002501void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2502 const SkRect* cullRect, const SkPaint& paint) {
2503 if (cullRect && this->quickReject(*cullRect)) {
2504 return;
2505 }
2506
2507 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2508
2509 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002510 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002511 }
2512
2513 LOOPER_END
2514}
2515
fmalita00d5c2c2014-08-21 08:53:26 -07002516void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2517 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002518
fmalita85d5eb92015-03-04 11:20:12 -08002519 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002520 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002521 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002522 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002523 SkRect tmp;
2524 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2525 return;
2526 }
2527 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002528 }
2529
fmalita024f9962015-03-03 19:08:17 -08002530 // We cannot filter in the looper as we normally do, because the paint is
2531 // incomplete at this point (text-related attributes are embedded within blob run paints).
2532 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002533 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002534
fmalita85d5eb92015-03-04 11:20:12 -08002535 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002536
fmalitaaa1b9122014-08-28 14:32:24 -07002537 while (iter.next()) {
2538 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002539 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002540 }
2541
fmalitaaa1b9122014-08-28 14:32:24 -07002542 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002543
2544 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002545}
2546
Cary Clark2a475ea2017-04-28 15:35:12 -04002547void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2548 this->drawText(string.c_str(), string.size(), x, y, paint);
2549}
2550
reed@google.come0d9ce82014-04-23 04:00:17 +00002551// These will become non-virtual, so they always call the (virtual) onDraw... method
2552void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2553 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002554 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002555 if (byteLength) {
2556 this->onDrawText(text, byteLength, x, y, paint);
2557 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002558}
2559void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2560 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002561 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002562 if (byteLength) {
2563 this->onDrawPosText(text, byteLength, pos, paint);
2564 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002565}
2566void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2567 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002568 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002569 if (byteLength) {
2570 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2571 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002572}
2573void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2574 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002575 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002576 if (byteLength) {
2577 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2578 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002579}
reed45561a02016-07-07 12:47:17 -07002580void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2581 const SkRect* cullRect, const SkPaint& paint) {
2582 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2583 if (byteLength) {
2584 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2585 }
2586}
fmalita00d5c2c2014-08-21 08:53:26 -07002587void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2588 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002589 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002590 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002591 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002592}
reed@google.come0d9ce82014-04-23 04:00:17 +00002593
Mike Reede88a1cb2017-03-17 09:50:46 -04002594void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2595 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002596 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2597 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2598
2599 while (iter.next()) {
2600 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002601 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002602 }
2603
2604 LOOPER_END
2605}
2606
dandovb3c9d1c2014-08-12 08:34:29 -07002607void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002608 const SkPoint texCoords[4], SkBlendMode bmode,
2609 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002610 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002611 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002612 return;
2613 }
mtklein6cfa73a2014-08-13 13:33:49 -07002614
Mike Reedfaba3712016-11-03 14:45:31 -04002615 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002616}
2617
2618void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002619 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002620 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002621 // Since a patch is always within the convex hull of the control points, we discard it when its
2622 // bounding rectangle is completely outside the current clip.
2623 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002624 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002625 if (this->quickReject(bounds)) {
2626 return;
2627 }
mtklein6cfa73a2014-08-13 13:33:49 -07002628
halcanary96fcdcc2015-08-27 07:41:13 -07002629 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002630
dandovecfff212014-08-04 10:02:00 -07002631 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002632 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002633 }
mtklein6cfa73a2014-08-13 13:33:49 -07002634
dandovecfff212014-08-04 10:02:00 -07002635 LOOPER_END
2636}
2637
reeda8db7282015-07-07 10:22:31 -07002638void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002639 RETURN_ON_NULL(dr);
2640 if (x || y) {
2641 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2642 this->onDrawDrawable(dr, &matrix);
2643 } else {
2644 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002645 }
2646}
2647
reeda8db7282015-07-07 10:22:31 -07002648void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002649 RETURN_ON_NULL(dr);
2650 if (matrix && matrix->isIdentity()) {
2651 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002652 }
reede3b38ce2016-01-08 09:18:44 -08002653 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002654}
2655
2656void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002657 // drawable bounds are no longer reliable (e.g. android displaylist)
2658 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002659 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002660}
2661
reed71c3c762015-06-24 10:29:17 -07002662void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002663 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002664 const SkRect* cull, const SkPaint* paint) {
2665 if (cull && this->quickReject(*cull)) {
2666 return;
2667 }
2668
2669 SkPaint pnt;
2670 if (paint) {
2671 pnt = *paint;
2672 }
halcanary9d524f22016-03-29 09:03:52 -07002673
halcanary96fcdcc2015-08-27 07:41:13 -07002674 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002675 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002676 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002677 }
2678 LOOPER_END
2679}
2680
reedf70b5312016-03-04 16:36:20 -08002681void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2682 SkASSERT(key);
2683
2684 SkPaint paint;
2685 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2686 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002687 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002688 }
2689 LOOPER_END
2690}
2691
reed@android.com8a1c16f2008-12-17 15:59:43 +00002692//////////////////////////////////////////////////////////////////////////////
2693// These methods are NOT virtual, and therefore must call back into virtual
2694// methods, rather than actually drawing themselves.
2695//////////////////////////////////////////////////////////////////////////////
2696
reed374772b2016-10-05 17:33:02 -07002697void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002698 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002699 SkPaint paint;
2700
2701 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002702 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002703 this->drawPaint(paint);
2704}
2705
2706void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002707 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002708 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002709 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2710}
2711
Mike Reed3661bc92017-02-22 13:21:42 -05002712void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002713 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002715
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716 pts[0].set(x0, y0);
2717 pts[1].set(x1, y1);
2718 this->drawPoints(kLines_PointMode, 2, pts, paint);
2719}
2720
Mike Reed3661bc92017-02-22 13:21:42 -05002721void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002722 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 if (radius < 0) {
2724 radius = 0;
2725 }
2726
2727 SkRect r;
2728 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002729 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730}
2731
2732void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2733 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002734 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002736 SkRRect rrect;
2737 rrect.setRectXY(r, rx, ry);
2738 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002739 } else {
2740 this->drawRect(r, paint);
2741 }
2742}
2743
reed@android.com8a1c16f2008-12-17 15:59:43 +00002744void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2745 SkScalar sweepAngle, bool useCenter,
2746 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002747 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002748 if (oval.isEmpty() || !sweepAngle) {
2749 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002750 }
bsalomon21af9ca2016-08-25 12:29:23 -07002751 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002752}
2753
2754void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2755 const SkPath& path, SkScalar hOffset,
2756 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002757 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002759
reed@android.com8a1c16f2008-12-17 15:59:43 +00002760 matrix.setTranslate(hOffset, vOffset);
2761 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2762}
2763
reed@android.comf76bacf2009-05-13 14:00:33 +00002764///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002765
2766/**
2767 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2768 * against the playback cost of recursing into the subpicture to get at its actual ops.
2769 *
2770 * For now we pick a conservatively small value, though measurement (and other heuristics like
2771 * the type of ops contained) may justify changing this value.
2772 */
2773#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002774
reedd5fa1a42014-08-09 11:08:05 -07002775void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002776 RETURN_ON_NULL(picture);
2777
reed1c2c4412015-04-30 13:09:24 -07002778 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002779 if (matrix && matrix->isIdentity()) {
2780 matrix = nullptr;
2781 }
2782 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2783 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2784 picture->playback(this);
2785 } else {
2786 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002787 }
2788}
robertphillips9b14f262014-06-04 05:40:44 -07002789
reedd5fa1a42014-08-09 11:08:05 -07002790void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2791 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002792 if (!paint || paint->canComputeFastBounds()) {
2793 SkRect bounds = picture->cullRect();
2794 if (paint) {
2795 paint->computeFastBounds(bounds, &bounds);
2796 }
2797 if (matrix) {
2798 matrix->mapRect(&bounds);
2799 }
2800 if (this->quickReject(bounds)) {
2801 return;
2802 }
2803 }
2804
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002805 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002806 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807}
2808
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809///////////////////////////////////////////////////////////////////////////////
2810///////////////////////////////////////////////////////////////////////////////
2811
reed3aafe112016-08-18 12:45:34 -07002812SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002813 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814
2815 SkASSERT(canvas);
2816
reed3aafe112016-08-18 12:45:34 -07002817 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002818 fDone = !fImpl->next();
2819}
2820
2821SkCanvas::LayerIter::~LayerIter() {
2822 fImpl->~SkDrawIter();
2823}
2824
2825void SkCanvas::LayerIter::next() {
2826 fDone = !fImpl->next();
2827}
2828
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002829SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002830 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831}
2832
2833const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002834 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002835}
2836
2837const SkPaint& SkCanvas::LayerIter::paint() const {
2838 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002839 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840 paint = &fDefaultPaint;
2841 }
2842 return *paint;
2843}
2844
Mike Reeda1361362017-03-07 09:37:29 -05002845void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2846 return fImpl->fDevice->onAsRgnClip(rgn);
2847}
2848
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2850int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002851
2852///////////////////////////////////////////////////////////////////////////////
2853
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002854static bool supported_for_raster_canvas(const SkImageInfo& info) {
2855 switch (info.alphaType()) {
2856 case kPremul_SkAlphaType:
2857 case kOpaque_SkAlphaType:
2858 break;
2859 default:
2860 return false;
2861 }
2862
2863 switch (info.colorType()) {
2864 case kAlpha_8_SkColorType:
2865 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002866 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002867 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002868 break;
2869 default:
2870 return false;
2871 }
2872
2873 return true;
2874}
2875
Mike Reed5df49342016-11-12 08:06:55 -06002876std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
2877 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002878 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002879 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002880 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002881
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002882 SkBitmap bitmap;
2883 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002884 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002885 }
Mike Reed5df49342016-11-12 08:06:55 -06002886 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002887}
reedd5fa1a42014-08-09 11:08:05 -07002888
2889///////////////////////////////////////////////////////////////////////////////
2890
2891SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002892 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002893 : fCanvas(canvas)
2894 , fSaveCount(canvas->getSaveCount())
2895{
bsalomon49f085d2014-09-05 13:34:00 -07002896 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002897 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002898 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002899 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002900 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002901 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002902 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002903 canvas->save();
2904 }
mtklein6cfa73a2014-08-13 13:33:49 -07002905
bsalomon49f085d2014-09-05 13:34:00 -07002906 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002907 canvas->concat(*matrix);
2908 }
2909}
2910
2911SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2912 fCanvas->restoreToCount(fSaveCount);
2913}
reede8f30622016-03-23 18:59:25 -07002914
Florin Malitaee424ac2016-12-01 12:47:59 -05002915///////////////////////////////////////////////////////////////////////////////
2916
2917SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2918 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2919
Florin Malita439ace92016-12-02 12:05:41 -05002920SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2921 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2922
Florin Malitaee424ac2016-12-01 12:47:59 -05002923SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2924 (void)this->INHERITED::getSaveLayerStrategy(rec);
2925 return kNoLayer_SaveLayerStrategy;
2926}
2927
2928///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002929
reed73603f32016-09-20 08:42:38 -07002930static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2931static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2932static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2933static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2934static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2935static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002936
2937///////////////////////////////////////////////////////////////////////////////////////////////////
2938
2939SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2940 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002941 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002942 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2943 SkIPoint origin = dev->getOrigin();
2944 SkMatrix ctm = this->getTotalMatrix();
2945 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2946
2947 SkIRect clip = fMCRec->fRasterClip.getBounds();
2948 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002949 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002950 clip.setEmpty();
2951 }
2952
2953 fAllocator->updateHandle(handle, ctm, clip);
2954 return handle;
2955 }
2956 return nullptr;
2957}
2958
2959static bool install(SkBitmap* bm, const SkImageInfo& info,
2960 const SkRasterHandleAllocator::Rec& rec) {
2961 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
2962 rec.fReleaseProc, rec.fReleaseCtx);
2963}
2964
2965SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2966 SkBitmap* bm) {
2967 SkRasterHandleAllocator::Rec rec;
2968 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2969 return nullptr;
2970 }
2971 return rec.fHandle;
2972}
2973
2974std::unique_ptr<SkCanvas>
2975SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2976 const SkImageInfo& info, const Rec* rec) {
2977 if (!alloc || !supported_for_raster_canvas(info)) {
2978 return nullptr;
2979 }
2980
2981 SkBitmap bm;
2982 Handle hndl;
2983
2984 if (rec) {
2985 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2986 } else {
2987 hndl = alloc->allocBitmap(info, &bm);
2988 }
2989 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2990}