blob: 150caa41ca9193c267d1baba6779ebf4c08080b0 [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
1802void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1803 uint32_t flags) {
1804 RETURN_ON_NULL(vertices);
1805 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001806}
1807
1808void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1809 this->onDrawPath(path, paint);
1810}
1811
reeda85d4d02015-05-06 12:56:48 -07001812void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001813 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001814 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001815}
1816
reede47829b2015-08-06 10:02:53 -07001817void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1818 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001819 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001820 if (dst.isEmpty() || src.isEmpty()) {
1821 return;
1822 }
1823 this->onDrawImageRect(image, &src, dst, paint, constraint);
1824}
reed41af9662015-01-05 07:49:08 -08001825
reed84984ef2015-07-17 07:09:43 -07001826void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1827 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001828 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001829 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001830}
1831
reede47829b2015-08-06 10:02:53 -07001832void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1833 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001834 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001835 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1836 constraint);
1837}
reede47829b2015-08-06 10:02:53 -07001838
reed4c21dc52015-06-25 12:32:03 -07001839void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1840 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001841 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001842 if (dst.isEmpty()) {
1843 return;
1844 }
msarett552bca92016-08-03 06:53:26 -07001845 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1846 this->onDrawImageNine(image, center, dst, paint);
1847 } else {
reede47829b2015-08-06 10:02:53 -07001848 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001849 }
reed4c21dc52015-06-25 12:32:03 -07001850}
1851
msarett16882062016-08-16 09:31:08 -07001852void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1853 const SkPaint* paint) {
1854 RETURN_ON_NULL(image);
1855 if (dst.isEmpty()) {
1856 return;
1857 }
msarett71df2d72016-09-30 12:41:42 -07001858
1859 SkIRect bounds;
1860 Lattice latticePlusBounds = lattice;
1861 if (!latticePlusBounds.fBounds) {
1862 bounds = SkIRect::MakeWH(image->width(), image->height());
1863 latticePlusBounds.fBounds = &bounds;
1864 }
1865
1866 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1867 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001868 } else {
1869 this->drawImageRect(image, dst, paint);
1870 }
1871}
1872
reed41af9662015-01-05 07:49:08 -08001873void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001874 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001875 return;
1876 }
reed41af9662015-01-05 07:49:08 -08001877 this->onDrawBitmap(bitmap, dx, dy, paint);
1878}
1879
reede47829b2015-08-06 10:02:53 -07001880void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001881 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001882 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001883 return;
1884 }
reede47829b2015-08-06 10:02:53 -07001885 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001886}
1887
reed84984ef2015-07-17 07:09:43 -07001888void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1889 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001890 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001891}
1892
reede47829b2015-08-06 10:02:53 -07001893void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1894 SrcRectConstraint constraint) {
1895 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1896 constraint);
1897}
reede47829b2015-08-06 10:02:53 -07001898
reed41af9662015-01-05 07:49:08 -08001899void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1900 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001901 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001902 return;
1903 }
msarett552bca92016-08-03 06:53:26 -07001904 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1905 this->onDrawBitmapNine(bitmap, center, dst, paint);
1906 } else {
reeda5517e22015-07-14 10:54:12 -07001907 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001908 }
reed41af9662015-01-05 07:49:08 -08001909}
1910
msarettc573a402016-08-02 08:05:56 -07001911void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1912 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001913 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001914 return;
1915 }
msarett71df2d72016-09-30 12:41:42 -07001916
1917 SkIRect bounds;
1918 Lattice latticePlusBounds = lattice;
1919 if (!latticePlusBounds.fBounds) {
1920 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1921 latticePlusBounds.fBounds = &bounds;
1922 }
1923
1924 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1925 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001926 } else {
msarett16882062016-08-16 09:31:08 -07001927 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001928 }
msarettc573a402016-08-02 08:05:56 -07001929}
1930
reed71c3c762015-06-24 10:29:17 -07001931void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001932 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001933 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001934 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001935 if (count <= 0) {
1936 return;
1937 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001938 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001939 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001940 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001941}
1942
reedf70b5312016-03-04 16:36:20 -08001943void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1944 if (key) {
1945 this->onDrawAnnotation(rect, key, value);
1946 }
1947}
1948
reede47829b2015-08-06 10:02:53 -07001949void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1950 const SkPaint* paint, SrcRectConstraint constraint) {
1951 if (src) {
1952 this->drawImageRect(image, *src, dst, paint, constraint);
1953 } else {
1954 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1955 dst, paint, constraint);
1956 }
1957}
1958void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1959 const SkPaint* paint, SrcRectConstraint constraint) {
1960 if (src) {
1961 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1962 } else {
1963 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1964 dst, paint, constraint);
1965 }
1966}
1967
tomhudsoncb3bd182016-05-18 07:24:16 -07001968void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1969 SkIRect layer_bounds = this->getTopLayerBounds();
1970 if (matrix) {
1971 *matrix = this->getTotalMatrix();
1972 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1973 }
1974 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001975 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001976 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1977 }
1978}
1979
reed@android.com8a1c16f2008-12-17 15:59:43 +00001980//////////////////////////////////////////////////////////////////////////////
1981// These are the virtual drawing methods
1982//////////////////////////////////////////////////////////////////////////////
1983
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001984void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001985 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001986 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1987 }
1988}
1989
reed41af9662015-01-05 07:49:08 -08001990void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001991 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001992 this->internalDrawPaint(paint);
1993}
1994
1995void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001996 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997
1998 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001999 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002000 }
2001
reed@google.com4e2b3d32011-04-07 14:18:59 +00002002 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002003}
2004
reed41af9662015-01-05 07:49:08 -08002005void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2006 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002007 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002008 if ((long)count <= 0) {
2009 return;
2010 }
2011
Mike Reed822128b2017-02-28 16:41:03 -05002012 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002013 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002014 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002015 // special-case 2 points (common for drawing a single line)
2016 if (2 == count) {
2017 r.set(pts[0], pts[1]);
2018 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002019 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002020 }
Mike Reed822128b2017-02-28 16:41:03 -05002021 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002022 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2023 return;
2024 }
2025 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002026 }
reed@google.coma584aed2012-05-16 14:06:02 +00002027
halcanary96fcdcc2015-08-27 07:41:13 -07002028 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002029
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002030 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002031
reed@android.com8a1c16f2008-12-17 15:59:43 +00002032 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002033 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002034 }
reed@google.com4b226022011-01-11 18:32:13 +00002035
reed@google.com4e2b3d32011-04-07 14:18:59 +00002036 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002037}
2038
reed4a167172016-08-18 17:15:25 -07002039static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2040 return ((intptr_t)paint.getImageFilter() |
2041#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2042 (intptr_t)canvas->getDrawFilter() |
2043#endif
2044 (intptr_t)paint.getLooper() ) != 0;
2045}
2046
reed41af9662015-01-05 07:49:08 -08002047void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002048 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002049 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002050 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2051 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2052 SkRect tmp(r);
2053 tmp.sort();
2054
Mike Reed822128b2017-02-28 16:41:03 -05002055 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002056 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2057 return;
2058 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002059 }
reed@google.com4b226022011-01-11 18:32:13 +00002060
reed4a167172016-08-18 17:15:25 -07002061 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002062 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002063
reed4a167172016-08-18 17:15:25 -07002064 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002065 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002066 }
2067
2068 LOOPER_END
2069 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002070 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002071 SkDrawIter iter(this);
2072 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002073 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002074 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002075 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002076}
2077
msarett44df6512016-08-25 13:54:30 -07002078void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002079 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002080 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002081 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002082 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2083 return;
2084 }
msarett44df6512016-08-25 13:54:30 -07002085 }
2086
Mike Reed822128b2017-02-28 16:41:03 -05002087 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002088
2089 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002090 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002091 }
2092
2093 LOOPER_END
2094}
2095
reed41af9662015-01-05 07:49:08 -08002096void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002097 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002098 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002099 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002100 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2101 return;
2102 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002103 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002104
Mike Reed822128b2017-02-28 16:41:03 -05002105 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002106
2107 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002108 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002109 }
2110
2111 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002112}
2113
bsalomonac3aa242016-08-19 11:25:19 -07002114void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2115 SkScalar sweepAngle, bool useCenter,
2116 const SkPaint& paint) {
2117 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002118 if (paint.canComputeFastBounds()) {
2119 SkRect storage;
2120 // Note we're using the entire oval as the bounds.
2121 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2122 return;
2123 }
bsalomonac3aa242016-08-19 11:25:19 -07002124 }
2125
Mike Reed822128b2017-02-28 16:41:03 -05002126 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002127
2128 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002129 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002130 }
2131
2132 LOOPER_END
2133}
2134
reed41af9662015-01-05 07:49:08 -08002135void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002136 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002137 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002138 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002139 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2140 return;
2141 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002142 }
2143
2144 if (rrect.isRect()) {
2145 // call the non-virtual version
2146 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002147 return;
2148 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002149 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002150 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2151 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002152 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002153
Mike Reed822128b2017-02-28 16:41:03 -05002154 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002155
2156 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002157 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002158 }
2159
2160 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002161}
2162
Mike Reed822128b2017-02-28 16:41:03 -05002163void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002164 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002165 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002166 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2167 return;
2168 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002169 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002170
Mike Reed822128b2017-02-28 16:41:03 -05002171 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002172
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002173 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002174 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002175 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002176
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002177 LOOPER_END
2178}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002179
reed41af9662015-01-05 07:49:08 -08002180void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002181 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002182 if (!path.isFinite()) {
2183 return;
2184 }
2185
Mike Reed822128b2017-02-28 16:41:03 -05002186 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002187 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002188 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002189 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2190 return;
2191 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002192 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002193
Mike Reed822128b2017-02-28 16:41:03 -05002194 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002195 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002196 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002197 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002198 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002199 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002200
Mike Reed822128b2017-02-28 16:41:03 -05002201 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002202
2203 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002204 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002205 }
2206
reed@google.com4e2b3d32011-04-07 14:18:59 +00002207 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002208}
2209
reed262a71b2015-12-05 13:07:27 -08002210bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002211 if (!paint.getImageFilter()) {
2212 return false;
2213 }
2214
2215 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002216 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002217 return false;
2218 }
2219
2220 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2221 // Once we can filter and the filter will return a result larger than itself, we should be
2222 // able to remove this constraint.
2223 // skbug.com/4526
2224 //
2225 SkPoint pt;
2226 ctm.mapXY(x, y, &pt);
2227 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2228 return ir.contains(fMCRec->fRasterClip.getBounds());
2229}
2230
reeda85d4d02015-05-06 12:56:48 -07002231void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002232 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002233 SkRect bounds = SkRect::MakeXYWH(x, y,
2234 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002235 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002236 SkRect tmp = bounds;
2237 if (paint) {
2238 paint->computeFastBounds(tmp, &tmp);
2239 }
2240 if (this->quickReject(tmp)) {
2241 return;
2242 }
reeda85d4d02015-05-06 12:56:48 -07002243 }
halcanary9d524f22016-03-29 09:03:52 -07002244
reeda85d4d02015-05-06 12:56:48 -07002245 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002246 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002247 paint = lazy.init();
2248 }
reed262a71b2015-12-05 13:07:27 -08002249
reeda2217ef2016-07-20 06:04:34 -07002250 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002251 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2252 *paint);
2253 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002254 special = this->getDevice()->makeSpecial(image);
2255 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002256 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002257 }
2258 }
2259
reed262a71b2015-12-05 13:07:27 -08002260 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2261
reeda85d4d02015-05-06 12:56:48 -07002262 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002263 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002264 if (special) {
2265 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002266 iter.fDevice->ctm().mapXY(x, y, &pt);
2267 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002268 SkScalarRoundToInt(pt.fX),
2269 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002270 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002271 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002272 }
reeda85d4d02015-05-06 12:56:48 -07002273 }
halcanary9d524f22016-03-29 09:03:52 -07002274
reeda85d4d02015-05-06 12:56:48 -07002275 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002276}
2277
reed41af9662015-01-05 07:49:08 -08002278void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002279 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002280 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002281 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002282 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002283 if (paint) {
2284 paint->computeFastBounds(dst, &storage);
2285 }
2286 if (this->quickReject(storage)) {
2287 return;
2288 }
reeda85d4d02015-05-06 12:56:48 -07002289 }
2290 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002291 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002292 paint = lazy.init();
2293 }
halcanary9d524f22016-03-29 09:03:52 -07002294
senorblancoc41e7e12015-12-07 12:51:30 -08002295 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002296 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002297
reeda85d4d02015-05-06 12:56:48 -07002298 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002299 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002300 }
halcanary9d524f22016-03-29 09:03:52 -07002301
reeda85d4d02015-05-06 12:56:48 -07002302 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002303}
2304
reed41af9662015-01-05 07:49:08 -08002305void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002306 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 SkDEBUGCODE(bitmap.validate();)
2308
reed33366972015-10-08 09:22:02 -07002309 if (bitmap.drawsNothing()) {
2310 return;
2311 }
2312
2313 SkLazyPaint lazy;
2314 if (nullptr == paint) {
2315 paint = lazy.init();
2316 }
2317
Mike Reed822128b2017-02-28 16:41:03 -05002318 SkRect bounds;
2319 bitmap.getBounds(&bounds);
2320 bounds.offset(x, y);
2321 bool canFastBounds = paint->canComputeFastBounds();
2322 if (canFastBounds) {
2323 SkRect storage;
2324 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002325 return;
2326 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002327 }
reed@google.com4b226022011-01-11 18:32:13 +00002328
reeda2217ef2016-07-20 06:04:34 -07002329 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002330 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2331 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002332 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002333 special = this->getDevice()->makeSpecial(bitmap);
2334 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002335 drawAsSprite = false;
2336 }
2337 }
2338
Mike Reed822128b2017-02-28 16:41:03 -05002339 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2340
2341 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002342
2343 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002344 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002345 if (special) {
reed262a71b2015-12-05 13:07:27 -08002346 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002347 iter.fDevice->ctm().mapXY(x, y, &pt);
2348 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002349 SkScalarRoundToInt(pt.fX),
2350 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002351 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002352 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002353 }
reed33366972015-10-08 09:22:02 -07002354 }
msarettfbfa2582016-08-12 08:29:08 -07002355
reed33366972015-10-08 09:22:02 -07002356 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002357}
2358
reed@google.com9987ec32011-09-07 11:57:52 +00002359// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002360void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002361 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002362 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002363 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364 return;
2365 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002366
halcanary96fcdcc2015-08-27 07:41:13 -07002367 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002368 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002369 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2370 return;
2371 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002372 }
reed@google.com3d608122011-11-21 15:16:16 +00002373
reed@google.com33535f32012-09-25 15:37:50 +00002374 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002375 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002376 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002377 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002378
senorblancoc41e7e12015-12-07 12:51:30 -08002379 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002380 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002381
reed@google.com33535f32012-09-25 15:37:50 +00002382 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002383 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002384 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002385
reed@google.com33535f32012-09-25 15:37:50 +00002386 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002387}
2388
reed41af9662015-01-05 07:49:08 -08002389void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002390 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002391 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002392 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002393 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002394}
2395
reed4c21dc52015-06-25 12:32:03 -07002396void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2397 const SkPaint* paint) {
2398 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002399
halcanary96fcdcc2015-08-27 07:41:13 -07002400 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002401 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002402 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2403 return;
2404 }
reed@google.com3d608122011-11-21 15:16:16 +00002405 }
halcanary9d524f22016-03-29 09:03:52 -07002406
reed4c21dc52015-06-25 12:32:03 -07002407 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002408 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002409 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002410 }
halcanary9d524f22016-03-29 09:03:52 -07002411
senorblancoc41e7e12015-12-07 12:51:30 -08002412 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002413
reed4c21dc52015-06-25 12:32:03 -07002414 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002415 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002416 }
halcanary9d524f22016-03-29 09:03:52 -07002417
reed4c21dc52015-06-25 12:32:03 -07002418 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002419}
2420
reed41af9662015-01-05 07:49:08 -08002421void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2422 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002423 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002424 SkDEBUGCODE(bitmap.validate();)
2425
halcanary96fcdcc2015-08-27 07:41:13 -07002426 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002427 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002428 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2429 return;
2430 }
reed4c21dc52015-06-25 12:32:03 -07002431 }
halcanary9d524f22016-03-29 09:03:52 -07002432
reed4c21dc52015-06-25 12:32:03 -07002433 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002434 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002435 paint = lazy.init();
2436 }
halcanary9d524f22016-03-29 09:03:52 -07002437
senorblancoc41e7e12015-12-07 12:51:30 -08002438 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002439
reed4c21dc52015-06-25 12:32:03 -07002440 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002441 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002442 }
halcanary9d524f22016-03-29 09:03:52 -07002443
reed4c21dc52015-06-25 12:32:03 -07002444 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002445}
2446
msarett16882062016-08-16 09:31:08 -07002447void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2448 const SkPaint* paint) {
2449 if (nullptr == paint || paint->canComputeFastBounds()) {
2450 SkRect storage;
2451 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2452 return;
2453 }
2454 }
2455
2456 SkLazyPaint lazy;
2457 if (nullptr == paint) {
2458 paint = lazy.init();
2459 }
2460
2461 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2462
2463 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002464 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002465 }
2466
2467 LOOPER_END
2468}
2469
2470void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2471 const SkRect& dst, const SkPaint* paint) {
2472 if (nullptr == paint || paint->canComputeFastBounds()) {
2473 SkRect storage;
2474 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2475 return;
2476 }
2477 }
2478
2479 SkLazyPaint lazy;
2480 if (nullptr == paint) {
2481 paint = lazy.init();
2482 }
2483
2484 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2485
2486 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002487 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002488 }
2489
2490 LOOPER_END
2491}
2492
reed@google.comf67e4cf2011-03-15 20:56:58 +00002493class SkDeviceFilteredPaint {
2494public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002495 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002496 uint32_t filteredFlags = device->filterTextFlags(paint);
2497 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002498 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002499 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002500 fPaint = newPaint;
2501 } else {
2502 fPaint = &paint;
2503 }
2504 }
2505
reed@google.comf67e4cf2011-03-15 20:56:58 +00002506 const SkPaint& paint() const { return *fPaint; }
2507
2508private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002509 const SkPaint* fPaint;
2510 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002511};
2512
reed@google.come0d9ce82014-04-23 04:00:17 +00002513void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2514 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002515 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002516
2517 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002518 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002519 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002520 }
2521
reed@google.com4e2b3d32011-04-07 14:18:59 +00002522 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002523}
2524
reed@google.come0d9ce82014-04-23 04:00:17 +00002525void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2526 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002527 SkPoint textOffset = SkPoint::Make(0, 0);
2528
halcanary96fcdcc2015-08-27 07:41:13 -07002529 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002530
reed@android.com8a1c16f2008-12-17 15:59:43 +00002531 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002532 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002533 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002534 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002535 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002536
reed@google.com4e2b3d32011-04-07 14:18:59 +00002537 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002538}
2539
reed@google.come0d9ce82014-04-23 04:00:17 +00002540void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2541 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002542
2543 SkPoint textOffset = SkPoint::Make(0, constY);
2544
halcanary96fcdcc2015-08-27 07:41:13 -07002545 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002546
reed@android.com8a1c16f2008-12-17 15:59:43 +00002547 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002548 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002549 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002550 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002551 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002552
reed@google.com4e2b3d32011-04-07 14:18:59 +00002553 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002554}
2555
reed@google.come0d9ce82014-04-23 04:00:17 +00002556void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2557 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002558 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002559
reed@android.com8a1c16f2008-12-17 15:59:43 +00002560 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002561 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002562 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002563 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002564
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002565 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002566}
2567
reed45561a02016-07-07 12:47:17 -07002568void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2569 const SkRect* cullRect, const SkPaint& paint) {
2570 if (cullRect && this->quickReject(*cullRect)) {
2571 return;
2572 }
2573
2574 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2575
2576 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002577 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002578 }
2579
2580 LOOPER_END
2581}
2582
fmalita00d5c2c2014-08-21 08:53:26 -07002583void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2584 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002585
fmalita85d5eb92015-03-04 11:20:12 -08002586 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002587 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002588 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002589 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002590 SkRect tmp;
2591 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2592 return;
2593 }
2594 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002595 }
2596
fmalita024f9962015-03-03 19:08:17 -08002597 // We cannot filter in the looper as we normally do, because the paint is
2598 // incomplete at this point (text-related attributes are embedded within blob run paints).
2599 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002600 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002601
fmalita85d5eb92015-03-04 11:20:12 -08002602 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002603
fmalitaaa1b9122014-08-28 14:32:24 -07002604 while (iter.next()) {
2605 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002606 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002607 }
2608
fmalitaaa1b9122014-08-28 14:32:24 -07002609 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002610
2611 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002612}
2613
reed@google.come0d9ce82014-04-23 04:00:17 +00002614// These will become non-virtual, so they always call the (virtual) onDraw... method
2615void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2616 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002617 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002618 if (byteLength) {
2619 this->onDrawText(text, byteLength, x, y, paint);
2620 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002621}
2622void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2623 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002624 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002625 if (byteLength) {
2626 this->onDrawPosText(text, byteLength, pos, paint);
2627 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002628}
2629void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2630 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002631 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002632 if (byteLength) {
2633 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2634 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002635}
2636void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2637 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002638 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002639 if (byteLength) {
2640 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2641 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002642}
reed45561a02016-07-07 12:47:17 -07002643void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2644 const SkRect* cullRect, const SkPaint& paint) {
2645 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2646 if (byteLength) {
2647 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2648 }
2649}
fmalita00d5c2c2014-08-21 08:53:26 -07002650void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2651 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002652 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002653 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002654 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002655}
reed@google.come0d9ce82014-04-23 04:00:17 +00002656
reed41af9662015-01-05 07:49:08 -08002657void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2658 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002659 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002660 const uint16_t indices[], int indexCount,
2661 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002662 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002663 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002664
reed@android.com8a1c16f2008-12-17 15:59:43 +00002665 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002666 iter.fDevice->drawVertices(vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002667 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002668 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002669 }
reed@google.com4b226022011-01-11 18:32:13 +00002670
reed@google.com4e2b3d32011-04-07 14:18:59 +00002671 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002672}
2673
Brian Salomon199fb872017-02-06 09:41:10 -05002674void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2675 const SkPaint& paint, uint32_t flags) {
2676 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2677 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2678
2679 while (iter.next()) {
2680 // In the common case of one iteration we could std::move vertices here.
Mike Reeda1361362017-03-07 09:37:29 -05002681 iter.fDevice->drawVerticesObject(vertices, bmode, looper.paint(), flags);
Brian Salomon199fb872017-02-06 09:41:10 -05002682 }
2683
2684 LOOPER_END
2685}
2686
2687void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2688 const SkPaint& paint, uint32_t flags) {
2689 const SkPoint* texs =
2690 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2691 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2692 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2693 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2694}
2695
dandovb3c9d1c2014-08-12 08:34:29 -07002696void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002697 const SkPoint texCoords[4], SkBlendMode bmode,
2698 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002699 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002700 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002701 return;
2702 }
mtklein6cfa73a2014-08-13 13:33:49 -07002703
Mike Reedfaba3712016-11-03 14:45:31 -04002704 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002705}
2706
2707void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002708 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002709 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002710 // Since a patch is always within the convex hull of the control points, we discard it when its
2711 // bounding rectangle is completely outside the current clip.
2712 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002713 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002714 if (this->quickReject(bounds)) {
2715 return;
2716 }
mtklein6cfa73a2014-08-13 13:33:49 -07002717
halcanary96fcdcc2015-08-27 07:41:13 -07002718 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002719
dandovecfff212014-08-04 10:02:00 -07002720 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002721 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002722 }
mtklein6cfa73a2014-08-13 13:33:49 -07002723
dandovecfff212014-08-04 10:02:00 -07002724 LOOPER_END
2725}
2726
reeda8db7282015-07-07 10:22:31 -07002727void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002728 RETURN_ON_NULL(dr);
2729 if (x || y) {
2730 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2731 this->onDrawDrawable(dr, &matrix);
2732 } else {
2733 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002734 }
2735}
2736
reeda8db7282015-07-07 10:22:31 -07002737void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002738 RETURN_ON_NULL(dr);
2739 if (matrix && matrix->isIdentity()) {
2740 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002741 }
reede3b38ce2016-01-08 09:18:44 -08002742 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002743}
2744
2745void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002746 // drawable bounds are no longer reliable (e.g. android displaylist)
2747 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002748 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002749}
2750
reed71c3c762015-06-24 10:29:17 -07002751void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002752 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002753 const SkRect* cull, const SkPaint* paint) {
2754 if (cull && this->quickReject(*cull)) {
2755 return;
2756 }
2757
2758 SkPaint pnt;
2759 if (paint) {
2760 pnt = *paint;
2761 }
halcanary9d524f22016-03-29 09:03:52 -07002762
halcanary96fcdcc2015-08-27 07:41:13 -07002763 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002764 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002765 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002766 }
2767 LOOPER_END
2768}
2769
reedf70b5312016-03-04 16:36:20 -08002770void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2771 SkASSERT(key);
2772
2773 SkPaint paint;
2774 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2775 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002776 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002777 }
2778 LOOPER_END
2779}
2780
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781//////////////////////////////////////////////////////////////////////////////
2782// These methods are NOT virtual, and therefore must call back into virtual
2783// methods, rather than actually drawing themselves.
2784//////////////////////////////////////////////////////////////////////////////
2785
Mike Reed3661bc92017-02-22 13:21:42 -05002786#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed374772b2016-10-05 17:33:02 -07002787void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002788 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002789 SkPaint paint;
2790
2791 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002792 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002793 this->drawPaint(paint);
2794}
Mike Reed3661bc92017-02-22 13:21:42 -05002795#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796
reed374772b2016-10-05 17:33:02 -07002797void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002798 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799 SkPaint paint;
2800
2801 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002802 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002803 this->drawPaint(paint);
2804}
2805
2806void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002807 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002808 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2810}
2811
Mike Reed3661bc92017-02-22 13:21:42 -05002812#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002813void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002814 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002815 SkPoint pt;
2816 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002817
reed@android.com8a1c16f2008-12-17 15:59:43 +00002818 pt.set(x, y);
2819 paint.setColor(color);
2820 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2821}
Mike Reed3661bc92017-02-22 13:21:42 -05002822#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823
Mike Reed3661bc92017-02-22 13:21:42 -05002824void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002825 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002827
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828 pts[0].set(x0, y0);
2829 pts[1].set(x1, y1);
2830 this->drawPoints(kLines_PointMode, 2, pts, paint);
2831}
2832
Mike Reed3661bc92017-02-22 13:21:42 -05002833#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002834void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2835 SkScalar right, SkScalar bottom,
2836 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002837 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002838 SkRect r;
2839
2840 r.set(left, top, right, bottom);
2841 this->drawRect(r, paint);
2842}
Mike Reed3661bc92017-02-22 13:21:42 -05002843#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002844
Mike Reed3661bc92017-02-22 13:21:42 -05002845void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002846 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847 if (radius < 0) {
2848 radius = 0;
2849 }
2850
2851 SkRect r;
2852 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002853 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002854}
2855
2856void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2857 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002858 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002859 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002860 SkRRect rrect;
2861 rrect.setRectXY(r, rx, ry);
2862 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002863 } else {
2864 this->drawRect(r, paint);
2865 }
2866}
2867
reed@android.com8a1c16f2008-12-17 15:59:43 +00002868void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2869 SkScalar sweepAngle, bool useCenter,
2870 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002871 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002872 if (oval.isEmpty() || !sweepAngle) {
2873 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002874 }
bsalomon21af9ca2016-08-25 12:29:23 -07002875 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002876}
2877
2878void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2879 const SkPath& path, SkScalar hOffset,
2880 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002881 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002882 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002883
reed@android.com8a1c16f2008-12-17 15:59:43 +00002884 matrix.setTranslate(hOffset, vOffset);
2885 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2886}
2887
reed@android.comf76bacf2009-05-13 14:00:33 +00002888///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002889
2890/**
2891 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2892 * against the playback cost of recursing into the subpicture to get at its actual ops.
2893 *
2894 * For now we pick a conservatively small value, though measurement (and other heuristics like
2895 * the type of ops contained) may justify changing this value.
2896 */
2897#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002898
reedd5fa1a42014-08-09 11:08:05 -07002899void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002900 RETURN_ON_NULL(picture);
2901
reed1c2c4412015-04-30 13:09:24 -07002902 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002903 if (matrix && matrix->isIdentity()) {
2904 matrix = nullptr;
2905 }
2906 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2907 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2908 picture->playback(this);
2909 } else {
2910 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002911 }
2912}
robertphillips9b14f262014-06-04 05:40:44 -07002913
reedd5fa1a42014-08-09 11:08:05 -07002914void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2915 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002916 if (!paint || paint->canComputeFastBounds()) {
2917 SkRect bounds = picture->cullRect();
2918 if (paint) {
2919 paint->computeFastBounds(bounds, &bounds);
2920 }
2921 if (matrix) {
2922 matrix->mapRect(&bounds);
2923 }
2924 if (this->quickReject(bounds)) {
2925 return;
2926 }
2927 }
2928
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002929 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002930 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002931}
2932
vjiaoblack95302da2016-07-21 10:25:54 -07002933#ifdef SK_EXPERIMENTAL_SHADOWING
2934void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2935 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002936 const SkPaint* paint,
2937 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002938 RETURN_ON_NULL(picture);
2939
2940 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2941
vjiaoblacke6f5d562016-08-25 06:30:23 -07002942 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002943}
2944
2945void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2946 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002947 const SkPaint* paint,
2948 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002949 if (!paint || paint->canComputeFastBounds()) {
2950 SkRect bounds = picture->cullRect();
2951 if (paint) {
2952 paint->computeFastBounds(bounds, &bounds);
2953 }
2954 if (matrix) {
2955 matrix->mapRect(&bounds);
2956 }
2957 if (this->quickReject(bounds)) {
2958 return;
2959 }
2960 }
2961
2962 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2963
vjiaoblacke6f5d562016-08-25 06:30:23 -07002964 sk_sp<SkImage> povDepthMap;
2965 sk_sp<SkImage> diffuseMap;
2966
vjiaoblack904527d2016-08-09 09:32:09 -07002967 // povDepthMap
2968 {
2969 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002970 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2971 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002972 sk_sp<SkLights> povLight = builder.finish();
2973
2974 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2975 picture->cullRect().height(),
2976 kBGRA_8888_SkColorType,
2977 kOpaque_SkAlphaType);
2978
2979 // Create a new surface (that matches the backend of canvas)
2980 // to create the povDepthMap
2981 sk_sp<SkSurface> surf(this->makeSurface(info));
2982
2983 // Wrap another SPFCanvas around the surface
2984 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2985 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2986
2987 // set the depth map canvas to have the light as the user's POV
2988 depthMapCanvas->setLights(std::move(povLight));
2989
2990 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002991 povDepthMap = surf->makeImageSnapshot();
2992 }
2993
2994 // diffuseMap
2995 {
2996 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2997 picture->cullRect().height(),
2998 kBGRA_8888_SkColorType,
2999 kOpaque_SkAlphaType);
3000
3001 sk_sp<SkSurface> surf(this->makeSurface(info));
3002 surf->getCanvas()->drawPicture(picture);
3003
3004 diffuseMap = surf->makeImageSnapshot();
3005 }
vjiaoblack904527d2016-08-09 09:32:09 -07003006
3007 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3008 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003009 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3010 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003011
3012 // TODO: pass the depth to the shader in vertices, or uniforms
3013 // so we don't have to render depth and color separately
3014 for (int i = 0; i < fLights->numLights(); ++i) {
3015 // skip over ambient lights; they don't cast shadows
3016 // lights that have shadow maps do not need updating (because lights are immutable)
3017 sk_sp<SkImage> depthMap;
3018 SkISize shMapSize;
3019
3020 if (fLights->light(i).getShadowMap() != nullptr) {
3021 continue;
3022 }
3023
3024 if (fLights->light(i).isRadial()) {
3025 shMapSize.fHeight = 1;
3026 shMapSize.fWidth = (int) picture->cullRect().width();
3027
3028 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3029 kBGRA_8888_SkColorType,
3030 kOpaque_SkAlphaType);
3031
3032 // Create new surface (that matches the backend of canvas)
3033 // for each shadow map
3034 sk_sp<SkSurface> surf(this->makeSurface(info));
3035
3036 // Wrap another SPFCanvas around the surface
3037 SkCanvas* depthMapCanvas = surf->getCanvas();
3038
3039 SkLights::Builder builder;
3040 builder.add(fLights->light(i));
3041 sk_sp<SkLights> curLight = builder.finish();
3042
3043 sk_sp<SkShader> shadowMapShader;
3044 shadowMapShader = SkRadialShadowMapShader::Make(
3045 povDepthShader, curLight,
3046 (int) picture->cullRect().width(),
3047 (int) picture->cullRect().height());
3048
3049 SkPaint shadowMapPaint;
3050 shadowMapPaint.setShader(std::move(shadowMapShader));
3051
3052 depthMapCanvas->setLights(curLight);
3053
3054 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3055 diffuseMap->height()),
3056 shadowMapPaint);
3057
3058 depthMap = surf->makeImageSnapshot();
3059
3060 } else {
3061 // TODO: compute the correct size of the depth map from the light properties
3062 // TODO: maybe add a kDepth_8_SkColorType
3063 // TODO: find actual max depth of picture
3064 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3065 fLights->light(i), 255,
3066 (int) picture->cullRect().width(),
3067 (int) picture->cullRect().height());
3068
3069 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3070 kBGRA_8888_SkColorType,
3071 kOpaque_SkAlphaType);
3072
3073 // Create a new surface (that matches the backend of canvas)
3074 // for each shadow map
3075 sk_sp<SkSurface> surf(this->makeSurface(info));
3076
3077 // Wrap another SPFCanvas around the surface
3078 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3079 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3080 depthMapCanvas->setShadowParams(params);
3081
3082 // set the depth map canvas to have the light we're drawing.
3083 SkLights::Builder builder;
3084 builder.add(fLights->light(i));
3085 sk_sp<SkLights> curLight = builder.finish();
3086 depthMapCanvas->setLights(std::move(curLight));
3087
3088 depthMapCanvas->drawPicture(picture);
3089 depthMap = surf->makeImageSnapshot();
3090 }
3091
3092 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3093 fLights->light(i).setShadowMap(std::move(depthMap));
3094 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3095 // we blur the variance map
3096 SkPaint blurPaint;
3097 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3098 params.fShadowRadius, nullptr));
3099
3100 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3101 kBGRA_8888_SkColorType,
3102 kOpaque_SkAlphaType);
3103
3104 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3105
3106 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3107
3108 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3109 }
3110 }
3111
3112 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003113 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3114 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003115 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003116 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003117 diffuseMap->height(),
3118 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003119
3120 shadowPaint.setShader(shadowShader);
3121
3122 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003123}
3124#endif
3125
reed@android.com8a1c16f2008-12-17 15:59:43 +00003126///////////////////////////////////////////////////////////////////////////////
3127///////////////////////////////////////////////////////////////////////////////
3128
reed3aafe112016-08-18 12:45:34 -07003129SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003130 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003131
3132 SkASSERT(canvas);
3133
reed3aafe112016-08-18 12:45:34 -07003134 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003135 fDone = !fImpl->next();
3136}
3137
3138SkCanvas::LayerIter::~LayerIter() {
3139 fImpl->~SkDrawIter();
3140}
3141
3142void SkCanvas::LayerIter::next() {
3143 fDone = !fImpl->next();
3144}
3145
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003146SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003147 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003148}
3149
3150const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003151 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003152}
3153
3154const SkPaint& SkCanvas::LayerIter::paint() const {
3155 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003156 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003157 paint = &fDefaultPaint;
3158 }
3159 return *paint;
3160}
3161
Mike Reeda1361362017-03-07 09:37:29 -05003162void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3163 return fImpl->fDevice->onAsRgnClip(rgn);
3164}
3165
reed@android.com8a1c16f2008-12-17 15:59:43 +00003166int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3167int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003168
3169///////////////////////////////////////////////////////////////////////////////
3170
Mike Reed8310f0e2017-03-08 21:42:37 +00003171SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
3172
3173///////////////////////////////////////////////////////////////////////////////
3174
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003175static bool supported_for_raster_canvas(const SkImageInfo& info) {
3176 switch (info.alphaType()) {
3177 case kPremul_SkAlphaType:
3178 case kOpaque_SkAlphaType:
3179 break;
3180 default:
3181 return false;
3182 }
3183
3184 switch (info.colorType()) {
3185 case kAlpha_8_SkColorType:
3186 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003187 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003188 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003189 break;
3190 default:
3191 return false;
3192 }
3193
3194 return true;
3195}
3196
Mike Reed5df49342016-11-12 08:06:55 -06003197std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3198 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003199 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003200 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003201 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003202
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003203 SkBitmap bitmap;
3204 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003205 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003206 }
Mike Reed5df49342016-11-12 08:06:55 -06003207 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003208}
reedd5fa1a42014-08-09 11:08:05 -07003209
3210///////////////////////////////////////////////////////////////////////////////
3211
3212SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003213 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003214 : fCanvas(canvas)
3215 , fSaveCount(canvas->getSaveCount())
3216{
bsalomon49f085d2014-09-05 13:34:00 -07003217 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003218 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003219 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003220 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003221 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003222 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003223 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003224 canvas->save();
3225 }
mtklein6cfa73a2014-08-13 13:33:49 -07003226
bsalomon49f085d2014-09-05 13:34:00 -07003227 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003228 canvas->concat(*matrix);
3229 }
3230}
3231
3232SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3233 fCanvas->restoreToCount(fSaveCount);
3234}
reede8f30622016-03-23 18:59:25 -07003235
Florin Malitaee424ac2016-12-01 12:47:59 -05003236///////////////////////////////////////////////////////////////////////////////
3237
3238SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3239 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3240
Florin Malita439ace92016-12-02 12:05:41 -05003241SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3242 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3243
Florin Malitaee424ac2016-12-01 12:47:59 -05003244SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3245 (void)this->INHERITED::getSaveLayerStrategy(rec);
3246 return kNoLayer_SaveLayerStrategy;
3247}
3248
3249///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003250
reed73603f32016-09-20 08:42:38 -07003251static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3252static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3253static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3254static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3255static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3256static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003257
3258///////////////////////////////////////////////////////////////////////////////////////////////////
3259
3260SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3261 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3262 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3263 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3264 SkIPoint origin = dev->getOrigin();
3265 SkMatrix ctm = this->getTotalMatrix();
3266 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3267
3268 SkIRect clip = fMCRec->fRasterClip.getBounds();
3269 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003270 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003271 clip.setEmpty();
3272 }
3273
3274 fAllocator->updateHandle(handle, ctm, clip);
3275 return handle;
3276 }
3277 return nullptr;
3278}
3279
3280static bool install(SkBitmap* bm, const SkImageInfo& info,
3281 const SkRasterHandleAllocator::Rec& rec) {
3282 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3283 rec.fReleaseProc, rec.fReleaseCtx);
3284}
3285
3286SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3287 SkBitmap* bm) {
3288 SkRasterHandleAllocator::Rec rec;
3289 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3290 return nullptr;
3291 }
3292 return rec.fHandle;
3293}
3294
3295std::unique_ptr<SkCanvas>
3296SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3297 const SkImageInfo& info, const Rec* rec) {
3298 if (!alloc || !supported_for_raster_canvas(info)) {
3299 return nullptr;
3300 }
3301
3302 SkBitmap bm;
3303 Handle hndl;
3304
3305 if (rec) {
3306 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3307 } else {
3308 hndl = alloc->allocBitmap(info, &bm);
3309 }
3310 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3311}