blob: ccdb71b5a0e6575ddde576b7828ef361cf71389d [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"
vjiaoblackb2796fd2016-09-09 09:22:39 -070031#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070035#include "SkShadowPaintFilterCanvas.h"
36#include "SkShadowShader.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000047#include "GrRenderTarget.h"
Brian Osman3b655982017-03-07 16:58:08 -050048#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050051#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050052#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
55
Mike Reed139e5e02017-03-08 11:29:33 -050056class SkNoPixelsDevice : public SkBaseDevice {
57public:
58 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
59 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
Mike Reed566e53c2017-03-10 10:49:45 -050060 {
Mike Reede393a622017-03-10 16:35:25 -050061 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
62 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050063 }
Mike Reed139e5e02017-03-08 11:29:33 -050064
65 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050066 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050067 this->privateResize(bounds.width(), bounds.height());
68 }
69
70protected:
71 // We don't track the clip at all (for performance), but we have to respond to some queries.
72 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
73 void onSave() override {}
74 void onRestore() override {}
75 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
76 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
77 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
78 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
79 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
80 bool onClipIsAA() const override { return false; }
81 void onAsRgnClip(SkRegion* rgn) const override {
82 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
83 }
84 ClipType onGetClipType() const override {
85 return kRect_ClipType;
86 }
87
88 void drawPaint(const SkPaint& paint) override {}
89 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
90 void drawRect(const SkRect&, const SkPaint&) override {}
91 void drawOval(const SkRect&, const SkPaint&) override {}
92 void drawRRect(const SkRRect&, const SkPaint&) override {}
93 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
94 void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {}
95 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
96 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
97 SkCanvas::SrcRectConstraint) override {}
98 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
99 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
100 const SkPaint&) override {}
101 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
102 void drawVertices(SkCanvas::VertexMode, int, const SkPoint[], const SkPoint[], const SkColor[],
103 SkBlendMode, const uint16_t[], int, const SkPaint&) override {}
104
105private:
106 typedef SkBaseDevice INHERITED;
107};
108
109///////////////////////////////////////////////////////////////////////////////////////////////////
110
reedc83a2972015-07-16 07:40:45 -0700111/*
112 * Return true if the drawing this rect would hit every pixels in the canvas.
113 *
114 * Returns false if
115 * - rect does not contain the canvas' bounds
116 * - paint is not fill
117 * - paint would blur or otherwise change the coverage of the rect
118 */
119bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
120 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700121 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
122 (int)kNone_ShaderOverrideOpacity,
123 "need_matching_enums0");
124 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
125 (int)kOpaque_ShaderOverrideOpacity,
126 "need_matching_enums1");
127 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
128 (int)kNotOpaque_ShaderOverrideOpacity,
129 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700130
131 const SkISize size = this->getBaseLayerSize();
132 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500133
134 // if we're clipped at all, we can't overwrite the entire surface
135 {
136 SkBaseDevice* base = this->getDevice();
137 SkBaseDevice* top = this->getTopDevice();
138 if (base != top) {
139 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
140 }
141 if (!base->clipIsWideOpen()) {
142 return false;
143 }
reedc83a2972015-07-16 07:40:45 -0700144 }
145
146 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700147 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700148 return false; // conservative
149 }
halcanaryc5769b22016-08-10 07:13:21 -0700150
151 SkRect devRect;
152 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
153 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700154 return false;
155 }
156 }
157
158 if (paint) {
159 SkPaint::Style paintStyle = paint->getStyle();
160 if (!(paintStyle == SkPaint::kFill_Style ||
161 paintStyle == SkPaint::kStrokeAndFill_Style)) {
162 return false;
163 }
164 if (paint->getMaskFilter() || paint->getLooper()
165 || paint->getPathEffect() || paint->getImageFilter()) {
166 return false; // conservative
167 }
168 }
169 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
170}
171
172///////////////////////////////////////////////////////////////////////////////////////////////////
173
reedd990e2f2014-12-22 11:58:30 -0800174static bool gIgnoreSaveLayerBounds;
175void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
176 gIgnoreSaveLayerBounds = ignore;
177}
178bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
179 return gIgnoreSaveLayerBounds;
180}
181
reed0acf1b42014-12-22 16:12:38 -0800182static bool gTreatSpriteAsBitmap;
183void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
184 gTreatSpriteAsBitmap = spriteAsBitmap;
185}
186bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
187 return gTreatSpriteAsBitmap;
188}
189
reed@google.comda17f752012-08-16 18:27:05 +0000190// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191//#define SK_TRACE_SAVERESTORE
192
193#ifdef SK_TRACE_SAVERESTORE
194 static int gLayerCounter;
195 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
196 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
197
198 static int gRecCounter;
199 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
200 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
201
202 static int gCanvasCounter;
203 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
204 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
205#else
206 #define inc_layer()
207 #define dec_layer()
208 #define inc_rec()
209 #define dec_rec()
210 #define inc_canvas()
211 #define dec_canvas()
212#endif
213
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000214typedef SkTLazy<SkPaint> SkLazyPaint;
215
reedc83a2972015-07-16 07:40:45 -0700216void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000217 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700218 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
219 ? SkSurface::kDiscard_ContentChangeMode
220 : SkSurface::kRetain_ContentChangeMode);
221 }
222}
223
224void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
225 ShaderOverrideOpacity overrideOpacity) {
226 if (fSurfaceBase) {
227 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
228 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
229 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
230 // and therefore we don't care which mode we're in.
231 //
232 if (fSurfaceBase->outstandingImageSnapshot()) {
233 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
234 mode = SkSurface::kDiscard_ContentChangeMode;
235 }
236 }
237 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000238 }
239}
240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000243/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 The clip/matrix/proc are fields that reflect the top of the save/restore
245 stack. Whenever the canvas changes, it marks a dirty flag, and then before
246 these are used (assuming we're not on a layer) we rebuild these cache
247 values: they reflect the top of the save stack, but translated and clipped
248 by the device's XY offset and bitmap-bounds.
249*/
250struct DeviceCM {
251 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000252 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000253 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000254 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700255 const SkMatrix* fMatrix;
256 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700257 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258
Mike Reeda1361362017-03-07 09:37:29 -0500259 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700260 : fNext(nullptr)
reed8c30a812016-04-20 16:36:51 -0700261 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700262 {
reed2c9e2002016-07-25 08:05:22 -0700263 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000264 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700265 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000266 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000268 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700269 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700270 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000271 }
reed@google.com4b226022011-01-11 18:32:13 +0000272
mtkleinfeaadee2015-04-08 11:25:48 -0700273 void reset(const SkIRect& bounds) {
274 SkASSERT(!fPaint);
275 SkASSERT(!fNext);
276 SkASSERT(fDevice);
277 fClip.setRect(bounds);
278 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279};
280
281/* This is the record we keep for each save/restore level in the stack.
282 Since a level optionally copies the matrix and/or stack, we have pointers
283 for these fields. If the value is copied for this level, the copy is
284 stored in the ...Storage field, and the pointer points to that. If the
285 value is not copied for this level, we ignore ...Storage, and just point
286 at the corresponding value in the previous level in the stack.
287*/
288class SkCanvas::MCRec {
289public:
reed1f836ee2014-07-07 07:49:34 -0700290 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700291 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 /* If there are any layers in the stack, this points to the top-most
293 one that is at or below this level in the stack (so we know what
294 bitmap/device to draw into from this level. This value is NOT
295 reference counted, since the real owner is either our fLayer field,
296 or a previous one in a lower level.)
297 */
Mike Reeda1361362017-03-07 09:37:29 -0500298 DeviceCM* fTopLayer;
299 SkConservativeClip fRasterClip;
300 SkMatrix fMatrix;
301 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302
vjiaoblacke5de1302016-07-13 14:05:28 -0700303 // This is the current cumulative depth (aggregate of all done translateZ calls)
304 SkScalar fCurDrawDepth;
305
Mike Reeda1361362017-03-07 09:37:29 -0500306 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700307 fFilter = nullptr;
308 fLayer = nullptr;
309 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800310 fMatrix.reset();
311 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700312 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700313
reedd9544982014-09-09 18:46:22 -0700314 // don't bother initializing fNext
315 inc_rec();
316 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700317 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
318 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700319 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700320 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700321 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800322 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700323
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324 // don't bother initializing fNext
325 inc_rec();
326 }
327 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000328 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700329 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 dec_rec();
331 }
mtkleinfeaadee2015-04-08 11:25:48 -0700332
333 void reset(const SkIRect& bounds) {
334 SkASSERT(fLayer);
335 SkASSERT(fDeferredSaveCount == 0);
336
337 fMatrix.reset();
338 fRasterClip.setRect(bounds);
339 fLayer->reset(bounds);
340 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341};
342
Mike Reeda1361362017-03-07 09:37:29 -0500343class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344public:
Mike Reeda1361362017-03-07 09:37:29 -0500345 SkDrawIter(SkCanvas* canvas)
346 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
347 {}
reed@google.com4b226022011-01-11 18:32:13 +0000348
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000350 const DeviceCM* rec = fCurrLayer;
351 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 fDevice = rec->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 fPaint = rec->fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700355 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 return true;
357 }
358 return false;
359 }
reed@google.com4b226022011-01-11 18:32:13 +0000360
reed@google.com6f8f2922011-03-04 22:27:10 +0000361 int getX() const { return fDevice->getOrigin().x(); }
362 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000364
Mike Reed99330ba2017-02-22 11:01:08 -0500365 SkBaseDevice* fDevice;
366
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368 const DeviceCM* fCurrLayer;
369 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370};
371
Mike Reed7627fa52017-02-08 10:07:53 -0500372#define FOR_EACH_TOP_DEVICE( code ) \
373 do { \
374 DeviceCM* layer = fMCRec->fTopLayer; \
375 while (layer) { \
376 SkBaseDevice* device = layer->fDevice; \
Mike Reedc42a1cd2017-02-14 14:25:14 -0500377 if (device) { \
378 code; \
379 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500380 layer = layer->fNext; \
381 } \
382 } while (0)
383
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384/////////////////////////////////////////////////////////////////////////////
385
reeddbc3cef2015-04-29 12:18:57 -0700386static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
387 return lazy->isValid() ? lazy->get() : lazy->set(orig);
388}
389
390/**
391 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700392 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700393 */
reedd053ce92016-03-22 10:17:23 -0700394static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700395 SkImageFilter* imgf = paint.getImageFilter();
396 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700397 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700398 }
399
reedd053ce92016-03-22 10:17:23 -0700400 SkColorFilter* imgCFPtr;
401 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700402 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700403 }
reedd053ce92016-03-22 10:17:23 -0700404 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700405
406 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700407 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700408 // there is no existing paint colorfilter, so we can just return the imagefilter's
409 return imgCF;
410 }
411
412 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
413 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700414 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700415}
416
senorblanco87e066e2015-10-28 11:23:36 -0700417/**
418 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
419 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
420 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
421 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
422 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
423 * conservative "effective" bounds based on the settings in the paint... with one exception. This
424 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
425 * deliberately ignored.
426 */
427static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
428 const SkRect& rawBounds,
429 SkRect* storage) {
430 SkPaint tmpUnfiltered(paint);
431 tmpUnfiltered.setImageFilter(nullptr);
432 if (tmpUnfiltered.canComputeFastBounds()) {
433 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
434 } else {
435 return rawBounds;
436 }
437}
438
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439class AutoDrawLooper {
440public:
senorblanco87e066e2015-10-28 11:23:36 -0700441 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
442 // paint. It's used to determine the size of the offscreen layer for filters.
443 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700444 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700445 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000446 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800447#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800449#else
450 fFilter = nullptr;
451#endif
reed4a8126e2014-09-22 07:29:03 -0700452 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000453 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700454 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000455 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456
reedd053ce92016-03-22 10:17:23 -0700457 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700458 if (simplifiedCF) {
459 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700460 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700461 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700462 fPaint = paint;
463 }
464
465 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700466 /**
467 * We implement ImageFilters for a given draw by creating a layer, then applying the
468 * imagefilter to the pixels of that layer (its backing surface/image), and then
469 * we call restore() to xfer that layer to the main canvas.
470 *
471 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
472 * 2. Generate the src pixels:
473 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
474 * return (fPaint). We then draw the primitive (using srcover) into a cleared
475 * buffer/surface.
476 * 3. Restore the layer created in #1
477 * The imagefilter is passed the buffer/surface from the layer (now filled with the
478 * src pixels of the primitive). It returns a new "filtered" buffer, which we
479 * draw onto the previous layer using the xfermode from the original paint.
480 */
reed@google.com8926b162012-03-23 15:36:36 +0000481 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500482 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700483 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700484 SkRect storage;
485 if (rawBounds) {
486 // Make rawBounds include all paint outsets except for those due to image filters.
487 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
488 }
reedbfd5f172016-01-07 11:28:08 -0800489 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700490 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700491 fTempLayerForImageFilter = true;
492 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000493 }
494
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000495 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500496 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000497 fIsSimple = false;
498 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700499 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000500 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700501 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000502 }
503 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000504
reed@android.com8a1c16f2008-12-17 15:59:43 +0000505 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700506 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000507 fCanvas->internalRestore();
508 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000509 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000510 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000511
reed@google.com4e2b3d32011-04-07 14:18:59 +0000512 const SkPaint& paint() const {
513 SkASSERT(fPaint);
514 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000516
reed@google.com129ec222012-05-15 13:24:09 +0000517 bool next(SkDrawFilter::Type drawType) {
518 if (fDone) {
519 return false;
520 } else if (fIsSimple) {
521 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000522 return !fPaint->nothingToDraw();
523 } else {
524 return this->doNext(drawType);
525 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000526 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000527
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500529 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700530 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000531 SkCanvas* fCanvas;
532 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000533 SkDrawFilter* fFilter;
534 const SkPaint* fPaint;
535 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700536 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000537 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000538 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000539 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500540 char fStorage[48];
541 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000542
543 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544};
545
reed@google.com129ec222012-05-15 13:24:09 +0000546bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700547 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000548 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700549 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000550
reeddbc3cef2015-04-29 12:18:57 -0700551 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
552 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000553
reed5c476fb2015-04-20 08:04:21 -0700554 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700555 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700556 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000557 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000558
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000559 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000560 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000561 return false;
562 }
563 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000564 if (!fFilter->filter(paint, drawType)) {
565 fDone = true;
566 return false;
567 }
halcanary96fcdcc2015-08-27 07:41:13 -0700568 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000569 // no looper means we only draw once
570 fDone = true;
571 }
572 }
573 fPaint = paint;
574
575 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000576 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000577 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000578 }
579
580 // call this after any possible paint modifiers
581 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700582 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000583 return false;
584 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000585 return true;
586}
587
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588////////// macros to place around the internal draw calls //////////////////
589
reed3aafe112016-08-18 12:45:34 -0700590#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
591 this->predrawNotify(); \
592 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
593 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800594 SkDrawIter iter(this);
595
596
reed@google.com8926b162012-03-23 15:36:36 +0000597#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000598 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700599 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000600 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000601 SkDrawIter iter(this);
602
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000603#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000604 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700605 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000606 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000607 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000608
reedc83a2972015-07-16 07:40:45 -0700609#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
610 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700611 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700612 while (looper.next(type)) { \
613 SkDrawIter iter(this);
614
reed@google.com4e2b3d32011-04-07 14:18:59 +0000615#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000616
617////////////////////////////////////////////////////////////////////////////
618
msarettfbfa2582016-08-12 08:29:08 -0700619static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
620 if (bounds.isEmpty()) {
621 return SkRect::MakeEmpty();
622 }
623
624 // Expand bounds out by 1 in case we are anti-aliasing. We store the
625 // bounds as floats to enable a faster quick reject implementation.
626 SkRect dst;
627 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
628 return dst;
629}
630
mtkleinfeaadee2015-04-08 11:25:48 -0700631void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
632 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700633 fMCRec->reset(bounds);
634
635 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500636 // know that the device is a SkNoPixelsDevice.
637 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice)->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700638 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700639 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700640}
641
reedd9544982014-09-09 18:46:22 -0700642SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800643 if (device && device->forceConservativeRasterClip()) {
644 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
645 }
reed42b73eb2015-11-20 13:42:42 -0800646
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000647 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800648 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700649 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700650#ifdef SK_EXPERIMENTAL_SHADOWING
651 fLights = nullptr;
652#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653
654 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500655 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500656 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700657 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658
reeda499f902015-05-01 09:34:31 -0700659 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
660 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Mike Reeda1361362017-03-07 09:37:29 -0500661 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700662
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664
halcanary96fcdcc2015-08-27 07:41:13 -0700665 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000666
reedf92c8662014-08-18 08:02:43 -0700667 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700668 // The root device and the canvas should always have the same pixel geometry
669 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700670 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800671 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700672 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500673
Mike Reedc42a1cd2017-02-14 14:25:14 -0500674 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700675 }
msarettfbfa2582016-08-12 08:29:08 -0700676
reedf92c8662014-08-18 08:02:43 -0700677 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678}
679
reed@google.comcde92112011-07-06 20:00:52 +0000680SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000681 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700682 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000683{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000684 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000685
halcanary96fcdcc2015-08-27 07:41:13 -0700686 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000687}
688
reed96a857e2015-01-25 10:33:58 -0800689SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000690 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800691 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000692{
693 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700694
Mike Reed566e53c2017-03-10 10:49:45 -0500695 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700696 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700697}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000698
reed78e27682014-11-19 08:04:34 -0800699SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700700 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700701 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700702{
703 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700704
Mike Reed566e53c2017-03-10 10:49:45 -0500705 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
706 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700707}
708
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000709SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000710 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700711 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000712{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000713 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700714
reedd9544982014-09-09 18:46:22 -0700715 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000716}
717
robertphillipsfcf78292015-06-19 11:49:52 -0700718SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
719 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700720 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700721{
722 inc_canvas();
723
724 this->init(device, flags);
725}
726
reed4a8126e2014-09-22 07:29:03 -0700727SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700728 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700729 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700730{
731 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700732
Hal Canary704cd322016-11-07 14:13:52 -0500733 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
734 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700735}
reed29c857d2014-09-21 10:25:07 -0700736
Mike Reed356f7c22017-01-10 11:58:39 -0500737SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
738 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700739 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
740 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500741 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700742{
743 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700744
Mike Reed356f7c22017-01-10 11:58:39 -0500745 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500746 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000747}
748
Mike Reed356f7c22017-01-10 11:58:39 -0500749SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
750
reed@android.com8a1c16f2008-12-17 15:59:43 +0000751SkCanvas::~SkCanvas() {
752 // free up the contents of our deque
753 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000754
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755 this->internalRestore(); // restore the last, since we're going away
756
halcanary385fe4d2015-08-26 13:07:48 -0700757 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000758
reed@android.com8a1c16f2008-12-17 15:59:43 +0000759 dec_canvas();
760}
761
fmalita53d9f1c2016-01-25 06:23:54 -0800762#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763SkDrawFilter* SkCanvas::getDrawFilter() const {
764 return fMCRec->fFilter;
765}
766
767SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700768 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
770 return filter;
771}
fmalita77650002016-01-21 18:47:11 -0800772#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000774SkMetaData& SkCanvas::getMetaData() {
775 // metadata users are rare, so we lazily allocate it. If that changes we
776 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700777 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000778 fMetaData = new SkMetaData;
779 }
780 return *fMetaData;
781}
782
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783///////////////////////////////////////////////////////////////////////////////
784
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000785void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700786 this->onFlush();
787}
788
789void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000790 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000791 if (device) {
792 device->flush();
793 }
794}
795
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000796SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000797 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000798 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
799}
800
senorblancoafc7cce2016-02-02 18:44:15 -0800801SkIRect SkCanvas::getTopLayerBounds() const {
802 SkBaseDevice* d = this->getTopDevice();
803 if (!d) {
804 return SkIRect::MakeEmpty();
805 }
806 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
807}
808
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000809SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000811 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812 SkASSERT(rec && rec->fLayer);
813 return rec->fLayer->fDevice;
814}
815
Florin Malita0ed3b642017-01-13 16:56:38 +0000816SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000817 return fMCRec->fTopLayer->fDevice;
818}
819
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000820bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000821 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700822 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700823 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000824 return false;
825 }
826 weAllocated = true;
827 }
828
reedcf01e312015-05-23 19:14:51 -0700829 SkAutoPixmapUnlock unlocker;
830 if (bitmap->requestLock(&unlocker)) {
831 const SkPixmap& pm = unlocker.pixmap();
832 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
833 return true;
834 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000835 }
836
837 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500838 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000839 }
840 return false;
841}
reed@google.com51df9e32010-12-23 19:29:18 +0000842
bsalomon@google.comc6980972011-11-02 19:57:21 +0000843bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000844 SkIRect r = srcRect;
845 const SkISize size = this->getBaseLayerSize();
846 if (!r.intersect(0, 0, size.width(), size.height())) {
847 bitmap->reset();
848 return false;
849 }
850
reed84825042014-09-02 12:50:45 -0700851 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000852 // bitmap will already be reset.
853 return false;
854 }
855 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
856 bitmap->reset();
857 return false;
858 }
859 return true;
860}
861
reed96472de2014-12-10 09:53:42 -0800862bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000863 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000864 if (!device) {
865 return false;
866 }
mtkleinf0f14112014-12-12 08:46:25 -0800867
Matt Sarett03dd6d52017-01-23 12:15:09 -0500868 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000869}
870
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000871bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700872 SkAutoPixmapUnlock unlocker;
873 if (bitmap.requestLock(&unlocker)) {
874 const SkPixmap& pm = unlocker.pixmap();
875 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000876 }
877 return false;
878}
879
Matt Sarett03dd6d52017-01-23 12:15:09 -0500880bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000881 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000882 SkBaseDevice* device = this->getDevice();
883 if (!device) {
884 return false;
885 }
886
Matt Sarett03dd6d52017-01-23 12:15:09 -0500887 // This check gives us an early out and prevents generation ID churn on the surface.
888 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
889 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
890 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
891 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000892 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000893
Matt Sarett03dd6d52017-01-23 12:15:09 -0500894 // Tell our owning surface to bump its generation ID.
895 const bool completeOverwrite =
896 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700897 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700898
Matt Sarett03dd6d52017-01-23 12:15:09 -0500899 // This can still fail, most notably in the case of a invalid color type or alpha type
900 // conversion. We could pull those checks into this function and avoid the unnecessary
901 // generation ID bump. But then we would be performing those checks twice, since they
902 // are also necessary at the bitmap/pixmap entry points.
903 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000904}
reed@google.com51df9e32010-12-23 19:29:18 +0000905
reed@android.com8a1c16f2008-12-17 15:59:43 +0000906//////////////////////////////////////////////////////////////////////////////
907
reed2ff1fce2014-12-11 07:07:37 -0800908void SkCanvas::checkForDeferredSave() {
909 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800910 this->doSave();
911 }
912}
913
reedf0090cb2014-11-26 08:55:51 -0800914int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800915#ifdef SK_DEBUG
916 int count = 0;
917 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
918 for (;;) {
919 const MCRec* rec = (const MCRec*)iter.next();
920 if (!rec) {
921 break;
922 }
923 count += 1 + rec->fDeferredSaveCount;
924 }
925 SkASSERT(count == fSaveCount);
926#endif
927 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800928}
929
930int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800931 fSaveCount += 1;
932 fMCRec->fDeferredSaveCount += 1;
933 return this->getSaveCount() - 1; // return our prev value
934}
935
936void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800937 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700938
939 SkASSERT(fMCRec->fDeferredSaveCount > 0);
940 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800941 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800942}
943
944void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800945 if (fMCRec->fDeferredSaveCount > 0) {
946 SkASSERT(fSaveCount > 1);
947 fSaveCount -= 1;
948 fMCRec->fDeferredSaveCount -= 1;
949 } else {
950 // check for underflow
951 if (fMCStack.count() > 1) {
952 this->willRestore();
953 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700954 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800955 this->internalRestore();
956 this->didRestore();
957 }
reedf0090cb2014-11-26 08:55:51 -0800958 }
959}
960
961void SkCanvas::restoreToCount(int count) {
962 // sanity check
963 if (count < 1) {
964 count = 1;
965 }
mtkleinf0f14112014-12-12 08:46:25 -0800966
reedf0090cb2014-11-26 08:55:51 -0800967 int n = this->getSaveCount() - count;
968 for (int i = 0; i < n; ++i) {
969 this->restore();
970 }
971}
972
reed2ff1fce2014-12-11 07:07:37 -0800973void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700975 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000977
Mike Reedc42a1cd2017-02-14 14:25:14 -0500978 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979}
980
reed4960eee2015-12-18 07:09:18 -0800981bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800982 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000983}
984
reed4960eee2015-12-18 07:09:18 -0800985bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700986 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500987 SkIRect clipBounds = this->getDeviceClipBounds();
988 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000989 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000990 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000991
reed96e657d2015-03-10 17:30:07 -0700992 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
993
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000994 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700995 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800996 if (bounds && !imageFilter->canComputeFastBounds()) {
997 bounds = nullptr;
998 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000999 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001000 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001001 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001002 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001003
reed96e657d2015-03-10 17:30:07 -07001004 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001005 r.roundOut(&ir);
1006 // early exit if the layer's bounds are clipped out
1007 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001008 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -05001009 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -07001010 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001011 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001012 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001013 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014 }
1015 } else { // no user bounds, so just use the clip
1016 ir = clipBounds;
1017 }
reed180aec42015-03-11 10:39:04 -07001018 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001019
reed4960eee2015-12-18 07:09:18 -08001020 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001021 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -07001022 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001023 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001024 }
1025
1026 if (intersection) {
1027 *intersection = ir;
1028 }
1029 return true;
1030}
1031
reed4960eee2015-12-18 07:09:18 -08001032
reed4960eee2015-12-18 07:09:18 -08001033int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1034 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001035}
1036
reed70ee31b2015-12-10 13:44:45 -08001037int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001038 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1039}
1040
1041int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1042 SaveLayerRec rec(origRec);
1043 if (gIgnoreSaveLayerBounds) {
1044 rec.fBounds = nullptr;
1045 }
1046 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1047 fSaveCount += 1;
1048 this->internalSaveLayer(rec, strategy);
1049 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001050}
1051
reeda2217ef2016-07-20 06:04:34 -07001052void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001053 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001054 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001055 SkDraw draw;
1056 SkRasterClip rc;
1057 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1058 if (!dst->accessPixels(&draw.fDst)) {
1059 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001060 }
reeda2217ef2016-07-20 06:04:34 -07001061 draw.fMatrix = &SkMatrix::I();
1062 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001063
1064 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001065 if (filter) {
1066 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1067 }
reeda2217ef2016-07-20 06:04:34 -07001068
Mike Reedc42a1cd2017-02-14 14:25:14 -05001069 int x = src->getOrigin().x() - dstOrigin.x();
1070 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001071 auto special = src->snapSpecial();
1072 if (special) {
Mike Reeda1361362017-03-07 09:37:29 -05001073 dst->drawSpecial(special.get(), x, y, p);
reeda2217ef2016-07-20 06:04:34 -07001074 }
robertphillips7354a4b2015-12-16 05:08:27 -08001075}
reed70ee31b2015-12-10 13:44:45 -08001076
reed129ed1c2016-02-22 06:42:31 -08001077static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1078 const SkPaint* paint) {
1079 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1080 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001081 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001082 const bool hasImageFilter = paint && paint->getImageFilter();
1083
1084 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1085 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1086 // force to L32
1087 return SkImageInfo::MakeN32(w, h, alphaType);
1088 } else {
1089 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001090 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001091 }
1092}
1093
reed4960eee2015-12-18 07:09:18 -08001094void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1095 const SkRect* bounds = rec.fBounds;
1096 const SkPaint* paint = rec.fPaint;
1097 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1098
reed8c30a812016-04-20 16:36:51 -07001099 SkLazyPaint lazyP;
1100 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1101 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001102 SkMatrix remainder;
1103 SkSize scale;
1104 /*
1105 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1106 * but they do handle scaling. To accommodate this, we do the following:
1107 *
1108 * 1. Stash off the current CTM
1109 * 2. Decompose the CTM into SCALE and REMAINDER
1110 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1111 * contains the REMAINDER
1112 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1113 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1114 * of the original imagefilter, and draw that (via drawSprite)
1115 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1116 *
1117 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1118 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1119 */
reed96a04f32016-04-25 09:25:15 -07001120 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001121 stashedMatrix.decomposeScale(&scale, &remainder))
1122 {
1123 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1124 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1125 SkPaint* p = lazyP.set(*paint);
1126 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1127 SkFilterQuality::kLow_SkFilterQuality,
1128 sk_ref_sp(imageFilter)));
1129 imageFilter = p->getImageFilter();
1130 paint = p;
1131 }
reed8c30a812016-04-20 16:36:51 -07001132
junov@chromium.orga907ac32012-02-24 21:54:07 +00001133 // do this before we create the layer. We don't call the public save() since
1134 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001135 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001136
junov@chromium.orga907ac32012-02-24 21:54:07 +00001137 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001138 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001139 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140 }
1141
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001142 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1143 // the clipRectBounds() call above?
1144 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001145 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001146 }
1147
reed4960eee2015-12-18 07:09:18 -08001148 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001149 SkPixelGeometry geo = fProps.pixelGeometry();
1150 if (paint) {
reed76033be2015-03-14 10:54:31 -07001151 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001152 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001153 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001154 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001155 }
1156 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157
robertphillips5139e502016-07-19 05:10:40 -07001158 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001159 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001160 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001161 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001162 }
reedb2db8982014-11-13 12:41:02 -08001163
robertphillips5139e502016-07-19 05:10:40 -07001164 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001165 paint);
1166
Hal Canary704cd322016-11-07 14:13:52 -05001167 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001168 {
reed70ee31b2015-12-10 13:44:45 -08001169 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001170 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001171 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001172 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001173 preserveLCDText,
1174 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001175 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1176 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001177 return;
reed61f501f2015-04-29 08:34:00 -07001178 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001179 }
Hal Canary704cd322016-11-07 14:13:52 -05001180 DeviceCM* layer =
Mike Reeda1361362017-03-07 09:37:29 -05001181 new DeviceCM(newDevice.get(), paint, this, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182
Mike Reedb43a3e02017-02-11 10:18:58 -05001183 // only have a "next" if this new layer doesn't affect the clip (rare)
1184 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001185 fMCRec->fLayer = layer;
1186 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001187
Mike Reedc61abee2017-02-28 17:45:27 -05001188 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001189 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001190 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001191 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001192
Mike Reedc42a1cd2017-02-14 14:25:14 -05001193 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1194
1195 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1196 if (layer->fNext) {
1197 // need to punch a hole in the previous device, so we don't draw there, given that
1198 // the new top-layer will allow drawing to happen "below" it.
1199 SkRegion hole(ir);
1200 do {
1201 layer = layer->fNext;
1202 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1203 } while (layer->fNext);
1204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001205}
1206
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001207int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001208 if (0xFF == alpha) {
1209 return this->saveLayer(bounds, nullptr);
1210 } else {
1211 SkPaint tmpPaint;
1212 tmpPaint.setAlpha(alpha);
1213 return this->saveLayer(bounds, &tmpPaint);
1214 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001215}
1216
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217void SkCanvas::internalRestore() {
1218 SkASSERT(fMCStack.count() != 0);
1219
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001220 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221 DeviceCM* layer = fMCRec->fLayer; // may be null
1222 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001223 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224
1225 // now do the normal restore()
1226 fMCRec->~MCRec(); // balanced in save()
1227 fMCStack.pop_back();
1228 fMCRec = (MCRec*)fMCStack.back();
1229
Mike Reedc42a1cd2017-02-14 14:25:14 -05001230 if (fMCRec) {
1231 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1232 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001233
reed@android.com8a1c16f2008-12-17 15:59:43 +00001234 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1235 since if we're being recorded, we don't want to record this (the
1236 recorder will have already recorded the restore).
1237 */
bsalomon49f085d2014-09-05 13:34:00 -07001238 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001239 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001240 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001241 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001242 // restore what we smashed in internalSaveLayer
1243 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001244 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001245 delete layer;
reedb679ca82015-04-07 04:40:48 -07001246 } else {
1247 // we're at the root
reeda499f902015-05-01 09:34:31 -07001248 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001249 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001250 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001252 }
msarettfbfa2582016-08-12 08:29:08 -07001253
1254 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001255 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001256 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1257 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001258}
1259
reede8f30622016-03-23 18:59:25 -07001260sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001261 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001262 props = &fProps;
1263 }
1264 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001265}
1266
reede8f30622016-03-23 18:59:25 -07001267sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001268 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001269 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001270}
1271
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001272SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001273 return this->onImageInfo();
1274}
1275
1276SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001277 SkBaseDevice* dev = this->getDevice();
1278 if (dev) {
1279 return dev->imageInfo();
1280 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001281 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001282 }
1283}
1284
brianosman898235c2016-04-06 07:38:23 -07001285bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001286 return this->onGetProps(props);
1287}
1288
1289bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001290 SkBaseDevice* dev = this->getDevice();
1291 if (dev) {
1292 if (props) {
1293 *props = fProps;
1294 }
1295 return true;
1296 } else {
1297 return false;
1298 }
1299}
1300
reed6ceeebd2016-03-09 14:26:26 -08001301bool SkCanvas::peekPixels(SkPixmap* pmap) {
1302 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001303}
1304
reed884e97c2015-05-26 11:31:54 -07001305bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001306 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001307 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001308}
1309
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001310void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001311 SkPixmap pmap;
1312 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001313 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001314 }
1315 if (info) {
1316 *info = pmap.info();
1317 }
1318 if (rowBytes) {
1319 *rowBytes = pmap.rowBytes();
1320 }
1321 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001322 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001323 }
reed884e97c2015-05-26 11:31:54 -07001324 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001325}
1326
reed884e97c2015-05-26 11:31:54 -07001327bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001328 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001329 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001330}
1331
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333
reed7503d602016-07-15 14:23:29 -07001334void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001336 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337 paint = &tmp;
1338 }
reed@google.com4b226022011-01-11 18:32:13 +00001339
reed@google.com8926b162012-03-23 15:36:36 +00001340 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001341
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001343 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001344 paint = &looper.paint();
1345 SkImageFilter* filter = paint->getImageFilter();
1346 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001347 if (filter) {
1348 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1349 if (specialImage) {
Mike Reeda1361362017-03-07 09:37:29 -05001350 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint);
Robert Phillips833dcf42016-11-18 08:44:13 -05001351 }
reed@google.com76dd2772012-01-05 21:15:07 +00001352 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001353 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001354 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001355 }
reeda2217ef2016-07-20 06:04:34 -07001356
reed@google.com4e2b3d32011-04-07 14:18:59 +00001357 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001358}
1359
reed32704672015-12-16 08:27:10 -08001360/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001361
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001362void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001363 if (dx || dy) {
1364 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001365 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001366
reedfe69b502016-09-12 06:31:48 -07001367 // Translate shouldn't affect the is-scale-translateness of the matrix.
1368 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001369
Mike Reedc42a1cd2017-02-14 14:25:14 -05001370 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001371
reedfe69b502016-09-12 06:31:48 -07001372 this->didTranslate(dx,dy);
1373 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001374}
1375
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001376void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001377 SkMatrix m;
1378 m.setScale(sx, sy);
1379 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001380}
1381
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001382void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001383 SkMatrix m;
1384 m.setRotate(degrees);
1385 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386}
1387
bungeman7438bfc2016-07-12 15:01:19 -07001388void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1389 SkMatrix m;
1390 m.setRotate(degrees, px, py);
1391 this->concat(m);
1392}
1393
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001394void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001395 SkMatrix m;
1396 m.setSkew(sx, sy);
1397 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001398}
1399
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001400void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001401 if (matrix.isIdentity()) {
1402 return;
1403 }
1404
reed2ff1fce2014-12-11 07:07:37 -08001405 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001406 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001407 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001408
Mike Reed7627fa52017-02-08 10:07:53 -05001409 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001410
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001411 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001412}
1413
reed8c30a812016-04-20 16:36:51 -07001414void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001415 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001416 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001417
Mike Reedc42a1cd2017-02-14 14:25:14 -05001418 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001419}
1420
1421void SkCanvas::setMatrix(const SkMatrix& matrix) {
1422 this->checkForDeferredSave();
1423 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001424 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001425}
1426
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001428 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429}
1430
vjiaoblack95302da2016-07-21 10:25:54 -07001431#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001432void SkCanvas::translateZ(SkScalar z) {
1433 this->checkForDeferredSave();
1434 this->fMCRec->fCurDrawDepth += z;
1435 this->didTranslateZ(z);
1436}
1437
1438SkScalar SkCanvas::getZ() const {
1439 return this->fMCRec->fCurDrawDepth;
1440}
1441
vjiaoblack95302da2016-07-21 10:25:54 -07001442void SkCanvas::setLights(sk_sp<SkLights> lights) {
1443 this->fLights = lights;
1444}
1445
1446sk_sp<SkLights> SkCanvas::getLights() const {
1447 return this->fLights;
1448}
1449#endif
1450
reed@android.com8a1c16f2008-12-17 15:59:43 +00001451//////////////////////////////////////////////////////////////////////////////
1452
Mike Reedc1f77742016-12-09 09:00:50 -05001453void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001454 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001455 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1456 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001457}
1458
Mike Reedc1f77742016-12-09 09:00:50 -05001459void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001460 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001461
Mike Reed7627fa52017-02-08 10:07:53 -05001462 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001463
reedc64eff52015-11-21 12:39:45 -08001464 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001465 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1466 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001467 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468}
1469
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001470void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1471 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001472 if (fClipRestrictionRect.isEmpty()) {
1473 // we notify the device, but we *dont* resolve deferred saves (since we're just
1474 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001475 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001476 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001477 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001478 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001479 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001480 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001481 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1482 }
1483}
1484
Mike Reedc1f77742016-12-09 09:00:50 -05001485void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001486 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001487 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001488 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001489 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1490 } else {
1491 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001492 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001493}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001494
Mike Reedc1f77742016-12-09 09:00:50 -05001495void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001496 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001497
Brian Salomona3b45d42016-10-03 11:36:16 -04001498 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001499
Mike Reed7627fa52017-02-08 10:07:53 -05001500 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001501
Brian Salomona3b45d42016-10-03 11:36:16 -04001502 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1503 isAA);
1504 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001505}
1506
Mike Reedc1f77742016-12-09 09:00:50 -05001507void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001508 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001509 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001510
1511 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1512 SkRect r;
1513 if (path.isRect(&r)) {
1514 this->onClipRect(r, op, edgeStyle);
1515 return;
1516 }
1517 SkRRect rrect;
1518 if (path.isOval(&r)) {
1519 rrect.setOval(r);
1520 this->onClipRRect(rrect, op, edgeStyle);
1521 return;
1522 }
1523 if (path.isRRect(&rrect)) {
1524 this->onClipRRect(rrect, op, edgeStyle);
1525 return;
1526 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001527 }
robertphillips39f05382015-11-24 09:30:12 -08001528
1529 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001530}
1531
Mike Reedc1f77742016-12-09 09:00:50 -05001532void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001533 AutoValidateClip avc(this);
1534
Brian Salomona3b45d42016-10-03 11:36:16 -04001535 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001536
Mike Reed7627fa52017-02-08 10:07:53 -05001537 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001538
Brian Salomona3b45d42016-10-03 11:36:16 -04001539 const SkPath* rasterClipPath = &path;
1540 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001541 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1542 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001543 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001544}
1545
Mike Reedc1f77742016-12-09 09:00:50 -05001546void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001547 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001548 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001549}
1550
Mike Reedc1f77742016-12-09 09:00:50 -05001551void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001552 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001553
reed@google.com5c3d1472011-02-22 19:12:23 +00001554 AutoValidateClip avc(this);
1555
reed73603f32016-09-20 08:42:38 -07001556 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001557 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558}
1559
reed@google.com819c9212011-02-23 18:56:55 +00001560#ifdef SK_DEBUG
1561void SkCanvas::validateClip() const {
1562 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001563 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001564 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001565 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001566 return;
1567 }
reed@google.com819c9212011-02-23 18:56:55 +00001568}
1569#endif
1570
Mike Reed8310f0e2017-03-08 21:42:37 +00001571void SkCanvas::replayClips(ClipVisitor* visitor) const {
1572#if 0
1573 SkClipStack::B2TIter iter(*fClipStack);
1574 const SkClipStack::Element* element;
1575
1576 while ((element = iter.next()) != nullptr) {
1577 element->replay(visitor);
1578 }
1579#endif
1580}
1581
Mike Reeda1361362017-03-07 09:37:29 -05001582bool SkCanvas::androidFramework_isClipAA() const {
1583 bool containsAA = false;
1584
1585 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1586
1587 return containsAA;
1588}
1589
1590class RgnAccumulator {
1591 SkRegion* fRgn;
1592public:
1593 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1594 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1595 SkIPoint origin = device->getOrigin();
1596 if (origin.x() | origin.y()) {
1597 rgn->translate(origin.x(), origin.y());
1598 }
1599 fRgn->op(*rgn, SkRegion::kUnion_Op);
1600 }
1601};
1602
1603void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1604 RgnAccumulator accum(rgn);
1605 SkRegion tmp;
1606
1607 rgn->setEmpty();
1608 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001609}
1610
reed@google.com5c3d1472011-02-22 19:12:23 +00001611///////////////////////////////////////////////////////////////////////////////
1612
reed@google.com754de5f2014-02-24 19:38:20 +00001613bool SkCanvas::isClipEmpty() const {
Mike Reeda1361362017-03-07 09:37:29 -05001614 SkBaseDevice* dev = this->getTopDevice();
1615 // if no device we return true
1616 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
reed@google.com754de5f2014-02-24 19:38:20 +00001617}
1618
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001619bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001620 SkBaseDevice* dev = this->getTopDevice();
1621 // if no device we return false
1622 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001623}
1624
msarettfbfa2582016-08-12 08:29:08 -07001625static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1626#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1627 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1628 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1629 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1630 return 0xF != _mm_movemask_ps(mask);
1631#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1632 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1633 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1634 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1635 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1636#else
1637 SkRect devRectAsRect;
1638 SkRect devClipAsRect;
1639 devRect.store(&devRectAsRect.fLeft);
1640 devClip.store(&devClipAsRect.fLeft);
1641 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1642#endif
1643}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001644
msarettfbfa2582016-08-12 08:29:08 -07001645// It's important for this function to not be inlined. Otherwise the compiler will share code
1646// between the fast path and the slow path, resulting in two slow paths.
1647static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1648 const SkMatrix& matrix) {
1649 SkRect deviceRect;
1650 matrix.mapRect(&deviceRect, src);
1651 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1652}
1653
1654bool SkCanvas::quickReject(const SkRect& src) const {
1655#ifdef SK_DEBUG
1656 // Verify that fDeviceClipBounds are set properly.
1657 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001658 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001659 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001660 } else {
msarettfbfa2582016-08-12 08:29:08 -07001661 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662 }
msarettfbfa2582016-08-12 08:29:08 -07001663
msarett9637ea92016-08-18 14:03:30 -07001664 // Verify that fIsScaleTranslate is set properly.
1665 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001666#endif
1667
msarett9637ea92016-08-18 14:03:30 -07001668 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001669 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1670 }
1671
1672 // We inline the implementation of mapScaleTranslate() for the fast path.
1673 float sx = fMCRec->fMatrix.getScaleX();
1674 float sy = fMCRec->fMatrix.getScaleY();
1675 float tx = fMCRec->fMatrix.getTranslateX();
1676 float ty = fMCRec->fMatrix.getTranslateY();
1677 Sk4f scale(sx, sy, sx, sy);
1678 Sk4f trans(tx, ty, tx, ty);
1679
1680 // Apply matrix.
1681 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1682
1683 // Make sure left < right, top < bottom.
1684 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1685 Sk4f min = Sk4f::Min(ltrb, rblt);
1686 Sk4f max = Sk4f::Max(ltrb, rblt);
1687 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1688 // ARM this sequence generates the fastest (a single instruction).
1689 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1690
1691 // Check if the device rect is NaN or outside the clip.
1692 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001693}
1694
reed@google.com3b3e8952012-08-16 20:53:31 +00001695bool SkCanvas::quickReject(const SkPath& path) const {
1696 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001697}
1698
Mike Reed42e8c532017-01-23 14:09:13 -05001699SkRect SkCanvas::onGetLocalClipBounds() const {
1700 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001701 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001702 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001703 }
1704
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001705 SkMatrix inverse;
1706 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001707 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001708 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001709 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001710
Mike Reed42e8c532017-01-23 14:09:13 -05001711 SkRect bounds;
1712 SkRect r;
1713 // adjust it outwards in case we are antialiasing
1714 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001715
Mike Reed42e8c532017-01-23 14:09:13 -05001716 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1717 ibounds.fRight + inset, ibounds.fBottom + inset);
1718 inverse.mapRect(&bounds, r);
1719 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001720}
1721
Mike Reed42e8c532017-01-23 14:09:13 -05001722SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001723 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001724}
1725
reed@android.com8a1c16f2008-12-17 15:59:43 +00001726const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001727 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001728}
1729
Brian Osman11052242016-10-27 14:47:55 -04001730GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001731 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001732 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001733}
1734
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001735GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001736 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001737 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001738}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001739
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001740void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1741 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001742 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001743 if (outer.isEmpty()) {
1744 return;
1745 }
1746 if (inner.isEmpty()) {
1747 this->drawRRect(outer, paint);
1748 return;
1749 }
1750
1751 // We don't have this method (yet), but technically this is what we should
1752 // be able to assert...
1753 // SkASSERT(outer.contains(inner));
1754 //
1755 // For now at least check for containment of bounds
1756 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1757
1758 this->onDrawDRRect(outer, inner, paint);
1759}
1760
reed41af9662015-01-05 07:49:08 -08001761// These need to stop being virtual -- clients need to override the onDraw... versions
1762
1763void SkCanvas::drawPaint(const SkPaint& paint) {
1764 this->onDrawPaint(paint);
1765}
1766
1767void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1768 this->onDrawRect(r, paint);
1769}
1770
msarettdca352e2016-08-26 06:37:45 -07001771void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1772 if (region.isEmpty()) {
1773 return;
1774 }
1775
1776 if (region.isRect()) {
1777 return this->drawIRect(region.getBounds(), paint);
1778 }
1779
1780 this->onDrawRegion(region, paint);
1781}
1782
reed41af9662015-01-05 07:49:08 -08001783void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1784 this->onDrawOval(r, paint);
1785}
1786
1787void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1788 this->onDrawRRect(rrect, paint);
1789}
1790
1791void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1792 this->onDrawPoints(mode, count, pts, paint);
1793}
1794
1795void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001796 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001797 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001798 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1799 indexCount, paint);
1800}
1801
Mike Reede88a1cb2017-03-17 09:50:46 -04001802void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1803 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001804 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001805 this->onDrawVerticesObject(vertices.get(), mode, paint);
1806}
1807
1808void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1809 RETURN_ON_NULL(vertices);
1810 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001811}
1812
1813void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1814 this->onDrawPath(path, paint);
1815}
1816
reeda85d4d02015-05-06 12:56:48 -07001817void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001818 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001819 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001820}
1821
reede47829b2015-08-06 10:02:53 -07001822void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1823 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001824 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001825 if (dst.isEmpty() || src.isEmpty()) {
1826 return;
1827 }
1828 this->onDrawImageRect(image, &src, dst, paint, constraint);
1829}
reed41af9662015-01-05 07:49:08 -08001830
reed84984ef2015-07-17 07:09:43 -07001831void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1832 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001833 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001834 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001835}
1836
reede47829b2015-08-06 10:02:53 -07001837void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1838 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001839 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001840 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1841 constraint);
1842}
reede47829b2015-08-06 10:02:53 -07001843
reed4c21dc52015-06-25 12:32:03 -07001844void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1845 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001846 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001847 if (dst.isEmpty()) {
1848 return;
1849 }
msarett552bca92016-08-03 06:53:26 -07001850 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1851 this->onDrawImageNine(image, center, dst, paint);
1852 } else {
reede47829b2015-08-06 10:02:53 -07001853 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001854 }
reed4c21dc52015-06-25 12:32:03 -07001855}
1856
msarett16882062016-08-16 09:31:08 -07001857void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1858 const SkPaint* paint) {
1859 RETURN_ON_NULL(image);
1860 if (dst.isEmpty()) {
1861 return;
1862 }
msarett71df2d72016-09-30 12:41:42 -07001863
1864 SkIRect bounds;
1865 Lattice latticePlusBounds = lattice;
1866 if (!latticePlusBounds.fBounds) {
1867 bounds = SkIRect::MakeWH(image->width(), image->height());
1868 latticePlusBounds.fBounds = &bounds;
1869 }
1870
1871 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1872 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001873 } else {
1874 this->drawImageRect(image, dst, paint);
1875 }
1876}
1877
reed41af9662015-01-05 07:49:08 -08001878void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001879 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001880 return;
1881 }
reed41af9662015-01-05 07:49:08 -08001882 this->onDrawBitmap(bitmap, dx, dy, paint);
1883}
1884
reede47829b2015-08-06 10:02:53 -07001885void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001886 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001887 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001888 return;
1889 }
reede47829b2015-08-06 10:02:53 -07001890 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001891}
1892
reed84984ef2015-07-17 07:09:43 -07001893void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1894 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001895 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001896}
1897
reede47829b2015-08-06 10:02:53 -07001898void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1899 SrcRectConstraint constraint) {
1900 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1901 constraint);
1902}
reede47829b2015-08-06 10:02:53 -07001903
reed41af9662015-01-05 07:49:08 -08001904void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1905 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001906 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001907 return;
1908 }
msarett552bca92016-08-03 06:53:26 -07001909 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1910 this->onDrawBitmapNine(bitmap, center, dst, paint);
1911 } else {
reeda5517e22015-07-14 10:54:12 -07001912 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001913 }
reed41af9662015-01-05 07:49:08 -08001914}
1915
msarettc573a402016-08-02 08:05:56 -07001916void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1917 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001918 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001919 return;
1920 }
msarett71df2d72016-09-30 12:41:42 -07001921
1922 SkIRect bounds;
1923 Lattice latticePlusBounds = lattice;
1924 if (!latticePlusBounds.fBounds) {
1925 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1926 latticePlusBounds.fBounds = &bounds;
1927 }
1928
1929 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1930 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001931 } else {
msarett16882062016-08-16 09:31:08 -07001932 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001933 }
msarettc573a402016-08-02 08:05:56 -07001934}
1935
reed71c3c762015-06-24 10:29:17 -07001936void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001937 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001938 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001939 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001940 if (count <= 0) {
1941 return;
1942 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001943 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001944 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001945 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001946}
1947
reedf70b5312016-03-04 16:36:20 -08001948void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1949 if (key) {
1950 this->onDrawAnnotation(rect, key, value);
1951 }
1952}
1953
reede47829b2015-08-06 10:02:53 -07001954void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1955 const SkPaint* paint, SrcRectConstraint constraint) {
1956 if (src) {
1957 this->drawImageRect(image, *src, dst, paint, constraint);
1958 } else {
1959 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1960 dst, paint, constraint);
1961 }
1962}
1963void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1964 const SkPaint* paint, SrcRectConstraint constraint) {
1965 if (src) {
1966 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1967 } else {
1968 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1969 dst, paint, constraint);
1970 }
1971}
1972
tomhudsoncb3bd182016-05-18 07:24:16 -07001973void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1974 SkIRect layer_bounds = this->getTopLayerBounds();
1975 if (matrix) {
1976 *matrix = this->getTotalMatrix();
1977 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1978 }
1979 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001980 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001981 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1982 }
1983}
1984
reed@android.com8a1c16f2008-12-17 15:59:43 +00001985//////////////////////////////////////////////////////////////////////////////
1986// These are the virtual drawing methods
1987//////////////////////////////////////////////////////////////////////////////
1988
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001989void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001990 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001991 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1992 }
1993}
1994
reed41af9662015-01-05 07:49:08 -08001995void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001996 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001997 this->internalDrawPaint(paint);
1998}
1999
2000void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002001 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002002
2003 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002004 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002005 }
2006
reed@google.com4e2b3d32011-04-07 14:18:59 +00002007 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002008}
2009
reed41af9662015-01-05 07:49:08 -08002010void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2011 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002012 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002013 if ((long)count <= 0) {
2014 return;
2015 }
2016
Mike Reed822128b2017-02-28 16:41:03 -05002017 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002018 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002019 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002020 // special-case 2 points (common for drawing a single line)
2021 if (2 == count) {
2022 r.set(pts[0], pts[1]);
2023 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002024 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002025 }
Mike Reed822128b2017-02-28 16:41:03 -05002026 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002027 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2028 return;
2029 }
2030 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002031 }
reed@google.coma584aed2012-05-16 14:06:02 +00002032
halcanary96fcdcc2015-08-27 07:41:13 -07002033 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002034
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002035 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002036
reed@android.com8a1c16f2008-12-17 15:59:43 +00002037 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002038 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002039 }
reed@google.com4b226022011-01-11 18:32:13 +00002040
reed@google.com4e2b3d32011-04-07 14:18:59 +00002041 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002042}
2043
reed4a167172016-08-18 17:15:25 -07002044static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2045 return ((intptr_t)paint.getImageFilter() |
2046#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2047 (intptr_t)canvas->getDrawFilter() |
2048#endif
2049 (intptr_t)paint.getLooper() ) != 0;
2050}
2051
reed41af9662015-01-05 07:49:08 -08002052void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002053 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002054 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002055 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2056 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2057 SkRect tmp(r);
2058 tmp.sort();
2059
Mike Reed822128b2017-02-28 16:41:03 -05002060 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002061 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2062 return;
2063 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002064 }
reed@google.com4b226022011-01-11 18:32:13 +00002065
reed4a167172016-08-18 17:15:25 -07002066 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002067 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002068
reed4a167172016-08-18 17:15:25 -07002069 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002070 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002071 }
2072
2073 LOOPER_END
2074 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002075 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002076 SkDrawIter iter(this);
2077 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002078 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002079 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002080 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002081}
2082
msarett44df6512016-08-25 13:54:30 -07002083void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002084 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002085 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002086 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002087 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2088 return;
2089 }
msarett44df6512016-08-25 13:54:30 -07002090 }
2091
Mike Reed822128b2017-02-28 16:41:03 -05002092 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002093
2094 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002095 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002096 }
2097
2098 LOOPER_END
2099}
2100
reed41af9662015-01-05 07:49:08 -08002101void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002102 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002103 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002104 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002105 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2106 return;
2107 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002108 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002109
Mike Reed822128b2017-02-28 16:41:03 -05002110 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002111
2112 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002113 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002114 }
2115
2116 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002117}
2118
bsalomonac3aa242016-08-19 11:25:19 -07002119void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2120 SkScalar sweepAngle, bool useCenter,
2121 const SkPaint& paint) {
2122 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002123 if (paint.canComputeFastBounds()) {
2124 SkRect storage;
2125 // Note we're using the entire oval as the bounds.
2126 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2127 return;
2128 }
bsalomonac3aa242016-08-19 11:25:19 -07002129 }
2130
Mike Reed822128b2017-02-28 16:41:03 -05002131 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002132
2133 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002134 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002135 }
2136
2137 LOOPER_END
2138}
2139
reed41af9662015-01-05 07:49:08 -08002140void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002141 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002142 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002143 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002144 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2145 return;
2146 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002147 }
2148
2149 if (rrect.isRect()) {
2150 // call the non-virtual version
2151 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002152 return;
2153 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002154 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002155 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2156 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002157 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002158
Mike Reed822128b2017-02-28 16:41:03 -05002159 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002160
2161 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002162 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002163 }
2164
2165 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002166}
2167
Mike Reed822128b2017-02-28 16:41:03 -05002168void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002169 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002170 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002171 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2172 return;
2173 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002174 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002175
Mike Reed822128b2017-02-28 16:41:03 -05002176 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002177
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002178 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002179 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002180 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002181
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002182 LOOPER_END
2183}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002184
reed41af9662015-01-05 07:49:08 -08002185void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002186 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002187 if (!path.isFinite()) {
2188 return;
2189 }
2190
Mike Reed822128b2017-02-28 16:41:03 -05002191 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002192 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002193 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002194 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2195 return;
2196 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002197 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002198
Mike Reed822128b2017-02-28 16:41:03 -05002199 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002200 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002201 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002202 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002203 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002205
Mike Reed822128b2017-02-28 16:41:03 -05002206 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002207
2208 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002209 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002210 }
2211
reed@google.com4e2b3d32011-04-07 14:18:59 +00002212 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002213}
2214
reed262a71b2015-12-05 13:07:27 -08002215bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002216 if (!paint.getImageFilter()) {
2217 return false;
2218 }
2219
2220 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002221 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002222 return false;
2223 }
2224
2225 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2226 // Once we can filter and the filter will return a result larger than itself, we should be
2227 // able to remove this constraint.
2228 // skbug.com/4526
2229 //
2230 SkPoint pt;
2231 ctm.mapXY(x, y, &pt);
2232 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2233 return ir.contains(fMCRec->fRasterClip.getBounds());
2234}
2235
reeda85d4d02015-05-06 12:56:48 -07002236void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002237 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002238 SkRect bounds = SkRect::MakeXYWH(x, y,
2239 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002240 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002241 SkRect tmp = bounds;
2242 if (paint) {
2243 paint->computeFastBounds(tmp, &tmp);
2244 }
2245 if (this->quickReject(tmp)) {
2246 return;
2247 }
reeda85d4d02015-05-06 12:56:48 -07002248 }
halcanary9d524f22016-03-29 09:03:52 -07002249
reeda85d4d02015-05-06 12:56:48 -07002250 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002251 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002252 paint = lazy.init();
2253 }
reed262a71b2015-12-05 13:07:27 -08002254
reeda2217ef2016-07-20 06:04:34 -07002255 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002256 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2257 *paint);
2258 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002259 special = this->getDevice()->makeSpecial(image);
2260 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002261 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002262 }
2263 }
2264
reed262a71b2015-12-05 13:07:27 -08002265 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2266
reeda85d4d02015-05-06 12:56:48 -07002267 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002268 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002269 if (special) {
2270 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002271 iter.fDevice->ctm().mapXY(x, y, &pt);
2272 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002273 SkScalarRoundToInt(pt.fX),
2274 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002275 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002276 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002277 }
reeda85d4d02015-05-06 12:56:48 -07002278 }
halcanary9d524f22016-03-29 09:03:52 -07002279
reeda85d4d02015-05-06 12:56:48 -07002280 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002281}
2282
reed41af9662015-01-05 07:49:08 -08002283void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002284 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002285 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002286 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002287 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002288 if (paint) {
2289 paint->computeFastBounds(dst, &storage);
2290 }
2291 if (this->quickReject(storage)) {
2292 return;
2293 }
reeda85d4d02015-05-06 12:56:48 -07002294 }
2295 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002296 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002297 paint = lazy.init();
2298 }
halcanary9d524f22016-03-29 09:03:52 -07002299
senorblancoc41e7e12015-12-07 12:51:30 -08002300 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002301 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002302
reeda85d4d02015-05-06 12:56:48 -07002303 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002304 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002305 }
halcanary9d524f22016-03-29 09:03:52 -07002306
reeda85d4d02015-05-06 12:56:48 -07002307 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002308}
2309
reed41af9662015-01-05 07:49:08 -08002310void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002311 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002312 SkDEBUGCODE(bitmap.validate();)
2313
reed33366972015-10-08 09:22:02 -07002314 if (bitmap.drawsNothing()) {
2315 return;
2316 }
2317
2318 SkLazyPaint lazy;
2319 if (nullptr == paint) {
2320 paint = lazy.init();
2321 }
2322
Mike Reed822128b2017-02-28 16:41:03 -05002323 SkRect bounds;
2324 bitmap.getBounds(&bounds);
2325 bounds.offset(x, y);
2326 bool canFastBounds = paint->canComputeFastBounds();
2327 if (canFastBounds) {
2328 SkRect storage;
2329 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002330 return;
2331 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002332 }
reed@google.com4b226022011-01-11 18:32:13 +00002333
reeda2217ef2016-07-20 06:04:34 -07002334 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002335 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2336 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002337 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002338 special = this->getDevice()->makeSpecial(bitmap);
2339 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002340 drawAsSprite = false;
2341 }
2342 }
2343
Mike Reed822128b2017-02-28 16:41:03 -05002344 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2345
2346 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002347
2348 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002349 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002350 if (special) {
reed262a71b2015-12-05 13:07:27 -08002351 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002352 iter.fDevice->ctm().mapXY(x, y, &pt);
2353 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002354 SkScalarRoundToInt(pt.fX),
2355 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002356 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002357 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002358 }
reed33366972015-10-08 09:22:02 -07002359 }
msarettfbfa2582016-08-12 08:29:08 -07002360
reed33366972015-10-08 09:22:02 -07002361 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002362}
2363
reed@google.com9987ec32011-09-07 11:57:52 +00002364// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002365void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002366 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002367 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002368 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002369 return;
2370 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002371
halcanary96fcdcc2015-08-27 07:41:13 -07002372 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002373 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002374 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2375 return;
2376 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002377 }
reed@google.com3d608122011-11-21 15:16:16 +00002378
reed@google.com33535f32012-09-25 15:37:50 +00002379 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002380 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002381 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002382 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002383
senorblancoc41e7e12015-12-07 12:51:30 -08002384 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002385 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002386
reed@google.com33535f32012-09-25 15:37:50 +00002387 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002388 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002389 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002390
reed@google.com33535f32012-09-25 15:37:50 +00002391 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002392}
2393
reed41af9662015-01-05 07:49:08 -08002394void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002395 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002396 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002397 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002398 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002399}
2400
reed4c21dc52015-06-25 12:32:03 -07002401void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2402 const SkPaint* paint) {
2403 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002404
halcanary96fcdcc2015-08-27 07:41:13 -07002405 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002406 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002407 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2408 return;
2409 }
reed@google.com3d608122011-11-21 15:16:16 +00002410 }
halcanary9d524f22016-03-29 09:03:52 -07002411
reed4c21dc52015-06-25 12:32:03 -07002412 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002413 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002414 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002415 }
halcanary9d524f22016-03-29 09:03:52 -07002416
senorblancoc41e7e12015-12-07 12:51:30 -08002417 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002418
reed4c21dc52015-06-25 12:32:03 -07002419 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002420 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002421 }
halcanary9d524f22016-03-29 09:03:52 -07002422
reed4c21dc52015-06-25 12:32:03 -07002423 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002424}
2425
reed41af9662015-01-05 07:49:08 -08002426void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2427 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002428 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002429 SkDEBUGCODE(bitmap.validate();)
2430
halcanary96fcdcc2015-08-27 07:41:13 -07002431 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002432 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002433 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2434 return;
2435 }
reed4c21dc52015-06-25 12:32:03 -07002436 }
halcanary9d524f22016-03-29 09:03:52 -07002437
reed4c21dc52015-06-25 12:32:03 -07002438 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002439 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002440 paint = lazy.init();
2441 }
halcanary9d524f22016-03-29 09:03:52 -07002442
senorblancoc41e7e12015-12-07 12:51:30 -08002443 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002444
reed4c21dc52015-06-25 12:32:03 -07002445 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002446 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002447 }
halcanary9d524f22016-03-29 09:03:52 -07002448
reed4c21dc52015-06-25 12:32:03 -07002449 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002450}
2451
msarett16882062016-08-16 09:31:08 -07002452void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2453 const SkPaint* paint) {
2454 if (nullptr == paint || paint->canComputeFastBounds()) {
2455 SkRect storage;
2456 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2457 return;
2458 }
2459 }
2460
2461 SkLazyPaint lazy;
2462 if (nullptr == paint) {
2463 paint = lazy.init();
2464 }
2465
2466 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2467
2468 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002469 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002470 }
2471
2472 LOOPER_END
2473}
2474
2475void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2476 const SkRect& dst, const SkPaint* paint) {
2477 if (nullptr == paint || paint->canComputeFastBounds()) {
2478 SkRect storage;
2479 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2480 return;
2481 }
2482 }
2483
2484 SkLazyPaint lazy;
2485 if (nullptr == paint) {
2486 paint = lazy.init();
2487 }
2488
2489 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2490
2491 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002492 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002493 }
2494
2495 LOOPER_END
2496}
2497
reed@google.comf67e4cf2011-03-15 20:56:58 +00002498class SkDeviceFilteredPaint {
2499public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002500 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002501 uint32_t filteredFlags = device->filterTextFlags(paint);
2502 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002503 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002504 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002505 fPaint = newPaint;
2506 } else {
2507 fPaint = &paint;
2508 }
2509 }
2510
reed@google.comf67e4cf2011-03-15 20:56:58 +00002511 const SkPaint& paint() const { return *fPaint; }
2512
2513private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002514 const SkPaint* fPaint;
2515 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002516};
2517
reed@google.come0d9ce82014-04-23 04:00:17 +00002518void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2519 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002520 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002521
2522 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002523 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002524 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002525 }
2526
reed@google.com4e2b3d32011-04-07 14:18:59 +00002527 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002528}
2529
reed@google.come0d9ce82014-04-23 04:00:17 +00002530void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2531 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002532 SkPoint textOffset = SkPoint::Make(0, 0);
2533
halcanary96fcdcc2015-08-27 07:41:13 -07002534 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002535
reed@android.com8a1c16f2008-12-17 15:59:43 +00002536 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002537 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002538 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002539 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002540 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002541
reed@google.com4e2b3d32011-04-07 14:18:59 +00002542 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543}
2544
reed@google.come0d9ce82014-04-23 04:00:17 +00002545void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2546 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002547
2548 SkPoint textOffset = SkPoint::Make(0, constY);
2549
halcanary96fcdcc2015-08-27 07:41:13 -07002550 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002551
reed@android.com8a1c16f2008-12-17 15:59:43 +00002552 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002553 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002554 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002555 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002556 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002557
reed@google.com4e2b3d32011-04-07 14:18:59 +00002558 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002559}
2560
reed@google.come0d9ce82014-04-23 04:00:17 +00002561void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2562 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002563 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002564
reed@android.com8a1c16f2008-12-17 15:59:43 +00002565 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002566 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002567 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002568 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002569
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002570 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002571}
2572
reed45561a02016-07-07 12:47:17 -07002573void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2574 const SkRect* cullRect, const SkPaint& paint) {
2575 if (cullRect && this->quickReject(*cullRect)) {
2576 return;
2577 }
2578
2579 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2580
2581 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002582 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002583 }
2584
2585 LOOPER_END
2586}
2587
fmalita00d5c2c2014-08-21 08:53:26 -07002588void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2589 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002590
fmalita85d5eb92015-03-04 11:20:12 -08002591 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002592 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002593 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002594 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002595 SkRect tmp;
2596 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2597 return;
2598 }
2599 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002600 }
2601
fmalita024f9962015-03-03 19:08:17 -08002602 // We cannot filter in the looper as we normally do, because the paint is
2603 // incomplete at this point (text-related attributes are embedded within blob run paints).
2604 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002605 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002606
fmalita85d5eb92015-03-04 11:20:12 -08002607 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002608
fmalitaaa1b9122014-08-28 14:32:24 -07002609 while (iter.next()) {
2610 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002611 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002612 }
2613
fmalitaaa1b9122014-08-28 14:32:24 -07002614 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002615
2616 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002617}
2618
reed@google.come0d9ce82014-04-23 04:00:17 +00002619// These will become non-virtual, so they always call the (virtual) onDraw... method
2620void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2621 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002622 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002623 if (byteLength) {
2624 this->onDrawText(text, byteLength, x, y, paint);
2625 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002626}
2627void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2628 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002629 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002630 if (byteLength) {
2631 this->onDrawPosText(text, byteLength, pos, paint);
2632 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002633}
2634void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2635 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002636 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002637 if (byteLength) {
2638 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2639 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002640}
2641void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2642 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002643 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002644 if (byteLength) {
2645 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2646 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002647}
reed45561a02016-07-07 12:47:17 -07002648void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2649 const SkRect* cullRect, const SkPaint& paint) {
2650 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2651 if (byteLength) {
2652 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2653 }
2654}
fmalita00d5c2c2014-08-21 08:53:26 -07002655void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2656 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002657 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002658 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002659 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002660}
reed@google.come0d9ce82014-04-23 04:00:17 +00002661
reed41af9662015-01-05 07:49:08 -08002662void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2663 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002664 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002665 const uint16_t indices[], int indexCount,
2666 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002667 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002668 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002669
reed@android.com8a1c16f2008-12-17 15:59:43 +00002670 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002671 iter.fDevice->drawVertices(vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002672 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002673 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002674 }
reed@google.com4b226022011-01-11 18:32:13 +00002675
reed@google.com4e2b3d32011-04-07 14:18:59 +00002676 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002677}
2678
Mike Reede88a1cb2017-03-17 09:50:46 -04002679void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2680 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002681 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2682 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2683
2684 while (iter.next()) {
2685 // In the common case of one iteration we could std::move vertices here.
Mike Reede88a1cb2017-03-17 09:50:46 -04002686 iter.fDevice->drawVerticesObject(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002687 }
2688
2689 LOOPER_END
2690}
2691
Mike Reede88a1cb2017-03-17 09:50:46 -04002692void SkCanvas::devolveSkVerticesToRaw(const SkVertices* vertices, SkBlendMode mode,
2693 const SkPaint& paint) {
Mike Reed5fa66452017-03-16 09:06:34 -04002694 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
Mike Reede88a1cb2017-03-17 09:50:46 -04002695 vertices->texCoords(), vertices->colors(), mode,
2696 vertices->indices(), vertices->indexCount(), paint);
Brian Salomon199fb872017-02-06 09:41:10 -05002697}
2698
dandovb3c9d1c2014-08-12 08:34:29 -07002699void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002700 const SkPoint texCoords[4], SkBlendMode bmode,
2701 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002702 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002703 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002704 return;
2705 }
mtklein6cfa73a2014-08-13 13:33:49 -07002706
Mike Reedfaba3712016-11-03 14:45:31 -04002707 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002708}
2709
2710void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002711 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002712 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002713 // Since a patch is always within the convex hull of the control points, we discard it when its
2714 // bounding rectangle is completely outside the current clip.
2715 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002716 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002717 if (this->quickReject(bounds)) {
2718 return;
2719 }
mtklein6cfa73a2014-08-13 13:33:49 -07002720
halcanary96fcdcc2015-08-27 07:41:13 -07002721 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002722
dandovecfff212014-08-04 10:02:00 -07002723 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002724 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002725 }
mtklein6cfa73a2014-08-13 13:33:49 -07002726
dandovecfff212014-08-04 10:02:00 -07002727 LOOPER_END
2728}
2729
reeda8db7282015-07-07 10:22:31 -07002730void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002731 RETURN_ON_NULL(dr);
2732 if (x || y) {
2733 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2734 this->onDrawDrawable(dr, &matrix);
2735 } else {
2736 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002737 }
2738}
2739
reeda8db7282015-07-07 10:22:31 -07002740void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002741 RETURN_ON_NULL(dr);
2742 if (matrix && matrix->isIdentity()) {
2743 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002744 }
reede3b38ce2016-01-08 09:18:44 -08002745 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002746}
2747
2748void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002749 // drawable bounds are no longer reliable (e.g. android displaylist)
2750 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002751 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002752}
2753
reed71c3c762015-06-24 10:29:17 -07002754void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002755 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002756 const SkRect* cull, const SkPaint* paint) {
2757 if (cull && this->quickReject(*cull)) {
2758 return;
2759 }
2760
2761 SkPaint pnt;
2762 if (paint) {
2763 pnt = *paint;
2764 }
halcanary9d524f22016-03-29 09:03:52 -07002765
halcanary96fcdcc2015-08-27 07:41:13 -07002766 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002767 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002768 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002769 }
2770 LOOPER_END
2771}
2772
reedf70b5312016-03-04 16:36:20 -08002773void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2774 SkASSERT(key);
2775
2776 SkPaint paint;
2777 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2778 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002779 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002780 }
2781 LOOPER_END
2782}
2783
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784//////////////////////////////////////////////////////////////////////////////
2785// These methods are NOT virtual, and therefore must call back into virtual
2786// methods, rather than actually drawing themselves.
2787//////////////////////////////////////////////////////////////////////////////
2788
Mike Reed3661bc92017-02-22 13:21:42 -05002789#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed374772b2016-10-05 17:33:02 -07002790void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002791 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002792 SkPaint paint;
2793
2794 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002795 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796 this->drawPaint(paint);
2797}
Mike Reed3661bc92017-02-22 13:21:42 -05002798#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799
reed374772b2016-10-05 17:33:02 -07002800void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002801 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002802 SkPaint paint;
2803
2804 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002805 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002806 this->drawPaint(paint);
2807}
2808
2809void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002810 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002811 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2813}
2814
Mike Reed3661bc92017-02-22 13:21:42 -05002815#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002817 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002818 SkPoint pt;
2819 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002820
reed@android.com8a1c16f2008-12-17 15:59:43 +00002821 pt.set(x, y);
2822 paint.setColor(color);
2823 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2824}
Mike Reed3661bc92017-02-22 13:21:42 -05002825#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826
Mike Reed3661bc92017-02-22 13:21:42 -05002827void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002828 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002829 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002830
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831 pts[0].set(x0, y0);
2832 pts[1].set(x1, y1);
2833 this->drawPoints(kLines_PointMode, 2, pts, paint);
2834}
2835
Mike Reed3661bc92017-02-22 13:21:42 -05002836#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2838 SkScalar right, SkScalar bottom,
2839 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002840 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002841 SkRect r;
2842
2843 r.set(left, top, right, bottom);
2844 this->drawRect(r, paint);
2845}
Mike Reed3661bc92017-02-22 13:21:42 -05002846#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847
Mike Reed3661bc92017-02-22 13:21:42 -05002848void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002849 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002850 if (radius < 0) {
2851 radius = 0;
2852 }
2853
2854 SkRect r;
2855 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002856 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002857}
2858
2859void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2860 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002861 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002862 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002863 SkRRect rrect;
2864 rrect.setRectXY(r, rx, ry);
2865 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002866 } else {
2867 this->drawRect(r, paint);
2868 }
2869}
2870
reed@android.com8a1c16f2008-12-17 15:59:43 +00002871void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2872 SkScalar sweepAngle, bool useCenter,
2873 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002874 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002875 if (oval.isEmpty() || !sweepAngle) {
2876 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002877 }
bsalomon21af9ca2016-08-25 12:29:23 -07002878 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002879}
2880
2881void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2882 const SkPath& path, SkScalar hOffset,
2883 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002884 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002885 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002886
reed@android.com8a1c16f2008-12-17 15:59:43 +00002887 matrix.setTranslate(hOffset, vOffset);
2888 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2889}
2890
reed@android.comf76bacf2009-05-13 14:00:33 +00002891///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002892
2893/**
2894 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2895 * against the playback cost of recursing into the subpicture to get at its actual ops.
2896 *
2897 * For now we pick a conservatively small value, though measurement (and other heuristics like
2898 * the type of ops contained) may justify changing this value.
2899 */
2900#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002901
reedd5fa1a42014-08-09 11:08:05 -07002902void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002903 RETURN_ON_NULL(picture);
2904
reed1c2c4412015-04-30 13:09:24 -07002905 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002906 if (matrix && matrix->isIdentity()) {
2907 matrix = nullptr;
2908 }
2909 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2910 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2911 picture->playback(this);
2912 } else {
2913 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002914 }
2915}
robertphillips9b14f262014-06-04 05:40:44 -07002916
reedd5fa1a42014-08-09 11:08:05 -07002917void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2918 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002919 if (!paint || paint->canComputeFastBounds()) {
2920 SkRect bounds = picture->cullRect();
2921 if (paint) {
2922 paint->computeFastBounds(bounds, &bounds);
2923 }
2924 if (matrix) {
2925 matrix->mapRect(&bounds);
2926 }
2927 if (this->quickReject(bounds)) {
2928 return;
2929 }
2930 }
2931
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002932 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002933 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002934}
2935
vjiaoblack95302da2016-07-21 10:25:54 -07002936#ifdef SK_EXPERIMENTAL_SHADOWING
2937void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2938 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002939 const SkPaint* paint,
2940 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002941 RETURN_ON_NULL(picture);
2942
2943 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2944
vjiaoblacke6f5d562016-08-25 06:30:23 -07002945 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002946}
2947
2948void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2949 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002950 const SkPaint* paint,
2951 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002952 if (!paint || paint->canComputeFastBounds()) {
2953 SkRect bounds = picture->cullRect();
2954 if (paint) {
2955 paint->computeFastBounds(bounds, &bounds);
2956 }
2957 if (matrix) {
2958 matrix->mapRect(&bounds);
2959 }
2960 if (this->quickReject(bounds)) {
2961 return;
2962 }
2963 }
2964
2965 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2966
vjiaoblacke6f5d562016-08-25 06:30:23 -07002967 sk_sp<SkImage> povDepthMap;
2968 sk_sp<SkImage> diffuseMap;
2969
vjiaoblack904527d2016-08-09 09:32:09 -07002970 // povDepthMap
2971 {
2972 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002973 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2974 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002975 sk_sp<SkLights> povLight = builder.finish();
2976
2977 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2978 picture->cullRect().height(),
2979 kBGRA_8888_SkColorType,
2980 kOpaque_SkAlphaType);
2981
2982 // Create a new surface (that matches the backend of canvas)
2983 // to create the povDepthMap
2984 sk_sp<SkSurface> surf(this->makeSurface(info));
2985
2986 // Wrap another SPFCanvas around the surface
2987 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2988 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2989
2990 // set the depth map canvas to have the light as the user's POV
2991 depthMapCanvas->setLights(std::move(povLight));
2992
2993 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002994 povDepthMap = surf->makeImageSnapshot();
2995 }
2996
2997 // diffuseMap
2998 {
2999 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3000 picture->cullRect().height(),
3001 kBGRA_8888_SkColorType,
3002 kOpaque_SkAlphaType);
3003
3004 sk_sp<SkSurface> surf(this->makeSurface(info));
3005 surf->getCanvas()->drawPicture(picture);
3006
3007 diffuseMap = surf->makeImageSnapshot();
3008 }
vjiaoblack904527d2016-08-09 09:32:09 -07003009
3010 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3011 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003012 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3013 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003014
3015 // TODO: pass the depth to the shader in vertices, or uniforms
3016 // so we don't have to render depth and color separately
3017 for (int i = 0; i < fLights->numLights(); ++i) {
3018 // skip over ambient lights; they don't cast shadows
3019 // lights that have shadow maps do not need updating (because lights are immutable)
3020 sk_sp<SkImage> depthMap;
3021 SkISize shMapSize;
3022
3023 if (fLights->light(i).getShadowMap() != nullptr) {
3024 continue;
3025 }
3026
3027 if (fLights->light(i).isRadial()) {
3028 shMapSize.fHeight = 1;
3029 shMapSize.fWidth = (int) picture->cullRect().width();
3030
3031 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3032 kBGRA_8888_SkColorType,
3033 kOpaque_SkAlphaType);
3034
3035 // Create new surface (that matches the backend of canvas)
3036 // for each shadow map
3037 sk_sp<SkSurface> surf(this->makeSurface(info));
3038
3039 // Wrap another SPFCanvas around the surface
3040 SkCanvas* depthMapCanvas = surf->getCanvas();
3041
3042 SkLights::Builder builder;
3043 builder.add(fLights->light(i));
3044 sk_sp<SkLights> curLight = builder.finish();
3045
3046 sk_sp<SkShader> shadowMapShader;
3047 shadowMapShader = SkRadialShadowMapShader::Make(
3048 povDepthShader, curLight,
3049 (int) picture->cullRect().width(),
3050 (int) picture->cullRect().height());
3051
3052 SkPaint shadowMapPaint;
3053 shadowMapPaint.setShader(std::move(shadowMapShader));
3054
3055 depthMapCanvas->setLights(curLight);
3056
3057 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3058 diffuseMap->height()),
3059 shadowMapPaint);
3060
3061 depthMap = surf->makeImageSnapshot();
3062
3063 } else {
3064 // TODO: compute the correct size of the depth map from the light properties
3065 // TODO: maybe add a kDepth_8_SkColorType
3066 // TODO: find actual max depth of picture
3067 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3068 fLights->light(i), 255,
3069 (int) picture->cullRect().width(),
3070 (int) picture->cullRect().height());
3071
3072 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3073 kBGRA_8888_SkColorType,
3074 kOpaque_SkAlphaType);
3075
3076 // Create a new surface (that matches the backend of canvas)
3077 // for each shadow map
3078 sk_sp<SkSurface> surf(this->makeSurface(info));
3079
3080 // Wrap another SPFCanvas around the surface
3081 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3082 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3083 depthMapCanvas->setShadowParams(params);
3084
3085 // set the depth map canvas to have the light we're drawing.
3086 SkLights::Builder builder;
3087 builder.add(fLights->light(i));
3088 sk_sp<SkLights> curLight = builder.finish();
3089 depthMapCanvas->setLights(std::move(curLight));
3090
3091 depthMapCanvas->drawPicture(picture);
3092 depthMap = surf->makeImageSnapshot();
3093 }
3094
3095 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3096 fLights->light(i).setShadowMap(std::move(depthMap));
3097 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3098 // we blur the variance map
3099 SkPaint blurPaint;
3100 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3101 params.fShadowRadius, nullptr));
3102
3103 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3104 kBGRA_8888_SkColorType,
3105 kOpaque_SkAlphaType);
3106
3107 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3108
3109 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3110
3111 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3112 }
3113 }
3114
3115 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003116 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3117 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003118 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003119 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003120 diffuseMap->height(),
3121 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003122
3123 shadowPaint.setShader(shadowShader);
3124
3125 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003126}
3127#endif
3128
reed@android.com8a1c16f2008-12-17 15:59:43 +00003129///////////////////////////////////////////////////////////////////////////////
3130///////////////////////////////////////////////////////////////////////////////
3131
reed3aafe112016-08-18 12:45:34 -07003132SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003133 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003134
3135 SkASSERT(canvas);
3136
reed3aafe112016-08-18 12:45:34 -07003137 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003138 fDone = !fImpl->next();
3139}
3140
3141SkCanvas::LayerIter::~LayerIter() {
3142 fImpl->~SkDrawIter();
3143}
3144
3145void SkCanvas::LayerIter::next() {
3146 fDone = !fImpl->next();
3147}
3148
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003149SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003150 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003151}
3152
3153const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003154 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003155}
3156
3157const SkPaint& SkCanvas::LayerIter::paint() const {
3158 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003159 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003160 paint = &fDefaultPaint;
3161 }
3162 return *paint;
3163}
3164
Mike Reeda1361362017-03-07 09:37:29 -05003165void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3166 return fImpl->fDevice->onAsRgnClip(rgn);
3167}
3168
reed@android.com8a1c16f2008-12-17 15:59:43 +00003169int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3170int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003171
3172///////////////////////////////////////////////////////////////////////////////
3173
Mike Reed8310f0e2017-03-08 21:42:37 +00003174SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
3175
3176///////////////////////////////////////////////////////////////////////////////
3177
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003178static bool supported_for_raster_canvas(const SkImageInfo& info) {
3179 switch (info.alphaType()) {
3180 case kPremul_SkAlphaType:
3181 case kOpaque_SkAlphaType:
3182 break;
3183 default:
3184 return false;
3185 }
3186
3187 switch (info.colorType()) {
3188 case kAlpha_8_SkColorType:
3189 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003190 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003191 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003192 break;
3193 default:
3194 return false;
3195 }
3196
3197 return true;
3198}
3199
Mike Reed5df49342016-11-12 08:06:55 -06003200std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3201 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003202 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003203 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003204 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003205
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003206 SkBitmap bitmap;
3207 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003208 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003209 }
Mike Reed5df49342016-11-12 08:06:55 -06003210 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003211}
reedd5fa1a42014-08-09 11:08:05 -07003212
3213///////////////////////////////////////////////////////////////////////////////
3214
3215SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003216 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003217 : fCanvas(canvas)
3218 , fSaveCount(canvas->getSaveCount())
3219{
bsalomon49f085d2014-09-05 13:34:00 -07003220 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003221 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003222 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003223 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003224 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003225 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003226 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003227 canvas->save();
3228 }
mtklein6cfa73a2014-08-13 13:33:49 -07003229
bsalomon49f085d2014-09-05 13:34:00 -07003230 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003231 canvas->concat(*matrix);
3232 }
3233}
3234
3235SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3236 fCanvas->restoreToCount(fSaveCount);
3237}
reede8f30622016-03-23 18:59:25 -07003238
Florin Malitaee424ac2016-12-01 12:47:59 -05003239///////////////////////////////////////////////////////////////////////////////
3240
3241SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3242 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3243
Florin Malita439ace92016-12-02 12:05:41 -05003244SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3245 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3246
Florin Malitaee424ac2016-12-01 12:47:59 -05003247SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3248 (void)this->INHERITED::getSaveLayerStrategy(rec);
3249 return kNoLayer_SaveLayerStrategy;
3250}
3251
3252///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003253
reed73603f32016-09-20 08:42:38 -07003254static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3255static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3256static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3257static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3258static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3259static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003260
3261///////////////////////////////////////////////////////////////////////////////////////////////////
3262
3263SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3264 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3265 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3266 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3267 SkIPoint origin = dev->getOrigin();
3268 SkMatrix ctm = this->getTotalMatrix();
3269 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3270
3271 SkIRect clip = fMCRec->fRasterClip.getBounds();
3272 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003273 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003274 clip.setEmpty();
3275 }
3276
3277 fAllocator->updateHandle(handle, ctm, clip);
3278 return handle;
3279 }
3280 return nullptr;
3281}
3282
3283static bool install(SkBitmap* bm, const SkImageInfo& info,
3284 const SkRasterHandleAllocator::Rec& rec) {
3285 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3286 rec.fReleaseProc, rec.fReleaseCtx);
3287}
3288
3289SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3290 SkBitmap* bm) {
3291 SkRasterHandleAllocator::Rec rec;
3292 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3293 return nullptr;
3294 }
3295 return rec.fHandle;
3296}
3297
3298std::unique_ptr<SkCanvas>
3299SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3300 const SkImageInfo& info, const Rec* rec) {
3301 if (!alloc || !supported_for_raster_canvas(info)) {
3302 return nullptr;
3303 }
3304
3305 SkBitmap bm;
3306 Handle hndl;
3307
3308 if (rec) {
3309 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3310 } else {
3311 hndl = alloc->allocBitmap(info, &bm);
3312 }
3313 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3314}