blob: 8fb83b46d0e47429a8ab048c2a9571bb2188d73d [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
Mike Reed986480a2017-01-13 22:43:16 +00008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080018#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070019#include "SkImageFilter.h"
20#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070021#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060022#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050025#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070026#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070027#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070028#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000029#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070030#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000031#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050032#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000033#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070034#include "SkShadowPaintFilterCanvas.h"
35#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000036#include "SkSmallAllocator.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"
bsalomon614d8f92016-07-13 15:42:40 -070048#include "SkGrPriv.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"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052
reede3b38ce2016-01-08 09:18:44 -080053#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
54
reedc83a2972015-07-16 07:40:45 -070055/*
56 * Return true if the drawing this rect would hit every pixels in the canvas.
57 *
58 * Returns false if
59 * - rect does not contain the canvas' bounds
60 * - paint is not fill
61 * - paint would blur or otherwise change the coverage of the rect
62 */
63bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
64 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070065 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
66 (int)kNone_ShaderOverrideOpacity,
67 "need_matching_enums0");
68 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
69 (int)kOpaque_ShaderOverrideOpacity,
70 "need_matching_enums1");
71 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
72 (int)kNotOpaque_ShaderOverrideOpacity,
73 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070074
75 const SkISize size = this->getBaseLayerSize();
76 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
77 if (!this->getClipStack()->quickContains(bounds)) {
78 return false;
79 }
80
81 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070082 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070083 return false; // conservative
84 }
halcanaryc5769b22016-08-10 07:13:21 -070085
86 SkRect devRect;
87 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
88 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070089 return false;
90 }
91 }
92
93 if (paint) {
94 SkPaint::Style paintStyle = paint->getStyle();
95 if (!(paintStyle == SkPaint::kFill_Style ||
96 paintStyle == SkPaint::kStrokeAndFill_Style)) {
97 return false;
98 }
99 if (paint->getMaskFilter() || paint->getLooper()
100 || paint->getPathEffect() || paint->getImageFilter()) {
101 return false; // conservative
102 }
103 }
104 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
105}
106
107///////////////////////////////////////////////////////////////////////////////////////////////////
108
reedd990e2f2014-12-22 11:58:30 -0800109static bool gIgnoreSaveLayerBounds;
110void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
111 gIgnoreSaveLayerBounds = ignore;
112}
113bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
114 return gIgnoreSaveLayerBounds;
115}
116
reed0acf1b42014-12-22 16:12:38 -0800117static bool gTreatSpriteAsBitmap;
118void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
119 gTreatSpriteAsBitmap = spriteAsBitmap;
120}
121bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
122 return gTreatSpriteAsBitmap;
123}
124
reed@google.comda17f752012-08-16 18:27:05 +0000125// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126//#define SK_TRACE_SAVERESTORE
127
128#ifdef SK_TRACE_SAVERESTORE
129 static int gLayerCounter;
130 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
131 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
132
133 static int gRecCounter;
134 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
135 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
136
137 static int gCanvasCounter;
138 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
139 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
140#else
141 #define inc_layer()
142 #define dec_layer()
143 #define inc_rec()
144 #define dec_rec()
145 #define inc_canvas()
146 #define dec_canvas()
147#endif
148
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000149typedef SkTLazy<SkPaint> SkLazyPaint;
150
reedc83a2972015-07-16 07:40:45 -0700151void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000152 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700153 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
154 ? SkSurface::kDiscard_ContentChangeMode
155 : SkSurface::kRetain_ContentChangeMode);
156 }
157}
158
159void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
160 ShaderOverrideOpacity overrideOpacity) {
161 if (fSurfaceBase) {
162 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
163 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
164 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
165 // and therefore we don't care which mode we're in.
166 //
167 if (fSurfaceBase->outstandingImageSnapshot()) {
168 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
169 mode = SkSurface::kDiscard_ContentChangeMode;
170 }
171 }
172 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000173 }
174}
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000178/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 The clip/matrix/proc are fields that reflect the top of the save/restore
180 stack. Whenever the canvas changes, it marks a dirty flag, and then before
181 these are used (assuming we're not on a layer) we rebuild these cache
182 values: they reflect the top of the save stack, but translated and clipped
183 by the device's XY offset and bitmap-bounds.
184*/
185struct DeviceCM {
186 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000187 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000188 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000189 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700190 const SkMatrix* fMatrix;
191 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700192 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193
reed96e657d2015-03-10 17:30:07 -0700194 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700195 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700196 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700197 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700198 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700199 {
reed2c9e2002016-07-25 08:05:22 -0700200 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000201 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700202 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000203 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000205 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700206 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700207 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000208 }
reed@google.com4b226022011-01-11 18:32:13 +0000209
mtkleinfeaadee2015-04-08 11:25:48 -0700210 void reset(const SkIRect& bounds) {
211 SkASSERT(!fPaint);
212 SkASSERT(!fNext);
213 SkASSERT(fDevice);
214 fClip.setRect(bounds);
215 }
216
reed@google.com045e62d2011-10-24 12:19:46 +0000217 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700218 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000219 int x = fDevice->getOrigin().x();
220 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 int width = fDevice->width();
222 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000223
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 if ((x | y) == 0) {
225 fMatrix = &totalMatrix;
226 fClip = totalClip;
227 } else {
228 fMatrixStorage = totalMatrix;
229 fMatrixStorage.postTranslate(SkIntToScalar(-x),
230 SkIntToScalar(-y));
231 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 totalClip.translate(-x, -y, &fClip);
234 }
235
reed@google.com045e62d2011-10-24 12:19:46 +0000236 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
238 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000241 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 SkRegion::kDifference_Op);
243 }
reed@google.com4b226022011-01-11 18:32:13 +0000244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245#ifdef SK_DEBUG
246 if (!fClip.isEmpty()) {
247 SkIRect deviceR;
248 deviceR.set(0, 0, width, height);
249 SkASSERT(deviceR.contains(fClip.getBounds()));
250 }
251#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000252 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253};
254
255/* This is the record we keep for each save/restore level in the stack.
256 Since a level optionally copies the matrix and/or stack, we have pointers
257 for these fields. If the value is copied for this level, the copy is
258 stored in the ...Storage field, and the pointer points to that. If the
259 value is not copied for this level, we ignore ...Storage, and just point
260 at the corresponding value in the previous level in the stack.
261*/
262class SkCanvas::MCRec {
263public:
reed1f836ee2014-07-07 07:49:34 -0700264 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700265 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 /* If there are any layers in the stack, this points to the top-most
267 one that is at or below this level in the stack (so we know what
268 bitmap/device to draw into from this level. This value is NOT
269 reference counted, since the real owner is either our fLayer field,
270 or a previous one in a lower level.)
271 */
reed2ff1fce2014-12-11 07:07:37 -0800272 DeviceCM* fTopLayer;
273 SkRasterClip fRasterClip;
274 SkMatrix fMatrix;
275 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276
vjiaoblacke5de1302016-07-13 14:05:28 -0700277 // This is the current cumulative depth (aggregate of all done translateZ calls)
278 SkScalar fCurDrawDepth;
279
reedd9544982014-09-09 18:46:22 -0700280 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700281 fFilter = nullptr;
282 fLayer = nullptr;
283 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800284 fMatrix.reset();
285 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700286 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700287
reedd9544982014-09-09 18:46:22 -0700288 // don't bother initializing fNext
289 inc_rec();
290 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700291 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
292 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700293 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700294 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700295 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800296 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700297
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 // don't bother initializing fNext
299 inc_rec();
300 }
301 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000302 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700303 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 dec_rec();
305 }
mtkleinfeaadee2015-04-08 11:25:48 -0700306
307 void reset(const SkIRect& bounds) {
308 SkASSERT(fLayer);
309 SkASSERT(fDeferredSaveCount == 0);
310
311 fMatrix.reset();
312 fRasterClip.setRect(bounds);
313 fLayer->reset(bounds);
314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315};
316
reed02f9ed72016-09-06 09:06:18 -0700317static SkIRect compute_device_bounds(SkBaseDevice* device) {
318 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
319 device->width(), device->height());
320}
321
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322class SkDrawIter : public SkDraw {
323public:
reed3aafe112016-08-18 12:45:34 -0700324 SkDrawIter(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 canvas->updateDeviceCMCache();
326
bungeman6bd52842016-10-27 09:30:08 -0700327 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700329
330 fMultiDeviceCS = nullptr;
331 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700332 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700333 fMultiDeviceCS->save();
334 }
335 }
336
337 ~SkDrawIter() {
338 if (fMultiDeviceCS) {
339 fMultiDeviceCS->restore();
340 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 }
reed@google.com4b226022011-01-11 18:32:13 +0000342
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700344 if (fMultiDeviceCS && fDevice) {
345 // remove the previous device's bounds
Mike Reedc1f77742016-12-09 09:00:50 -0500346 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), kDifference_SkClipOp);
reed02f9ed72016-09-06 09:06:18 -0700347 }
348
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700350 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
351 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 }
353
reed@google.comf68c5e22012-02-24 16:38:58 +0000354 const DeviceCM* rec = fCurrLayer;
355 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356
357 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000358 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700360 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700361 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700362 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000364 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365
366 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700367 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000368
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 return true;
370 }
371 return false;
372 }
reed@google.com4b226022011-01-11 18:32:13 +0000373
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000374 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700375 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000376 int getX() const { return fDevice->getOrigin().x(); }
377 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000380
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382 const DeviceCM* fCurrLayer;
383 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700384 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385
386 typedef SkDraw INHERITED;
387};
388
389/////////////////////////////////////////////////////////////////////////////
390
reeddbc3cef2015-04-29 12:18:57 -0700391static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
392 return lazy->isValid() ? lazy->get() : lazy->set(orig);
393}
394
395/**
396 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700397 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700398 */
reedd053ce92016-03-22 10:17:23 -0700399static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700400 SkImageFilter* imgf = paint.getImageFilter();
401 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700402 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700403 }
404
reedd053ce92016-03-22 10:17:23 -0700405 SkColorFilter* imgCFPtr;
406 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700407 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700408 }
reedd053ce92016-03-22 10:17:23 -0700409 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700410
411 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700412 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700413 // there is no existing paint colorfilter, so we can just return the imagefilter's
414 return imgCF;
415 }
416
417 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
418 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700419 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700420}
421
senorblanco87e066e2015-10-28 11:23:36 -0700422/**
423 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
424 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
425 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
426 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
427 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
428 * conservative "effective" bounds based on the settings in the paint... with one exception. This
429 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
430 * deliberately ignored.
431 */
432static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
433 const SkRect& rawBounds,
434 SkRect* storage) {
435 SkPaint tmpUnfiltered(paint);
436 tmpUnfiltered.setImageFilter(nullptr);
437 if (tmpUnfiltered.canComputeFastBounds()) {
438 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
439 } else {
440 return rawBounds;
441 }
442}
443
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444class AutoDrawLooper {
445public:
senorblanco87e066e2015-10-28 11:23:36 -0700446 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
447 // paint. It's used to determine the size of the offscreen layer for filters.
448 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700449 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700450 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000451 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800452#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800454#else
455 fFilter = nullptr;
456#endif
reed4a8126e2014-09-22 07:29:03 -0700457 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000458 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700459 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000460 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000461
reedd053ce92016-03-22 10:17:23 -0700462 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700463 if (simplifiedCF) {
464 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700465 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700466 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700467 fPaint = paint;
468 }
469
470 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700471 /**
472 * We implement ImageFilters for a given draw by creating a layer, then applying the
473 * imagefilter to the pixels of that layer (its backing surface/image), and then
474 * we call restore() to xfer that layer to the main canvas.
475 *
476 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
477 * 2. Generate the src pixels:
478 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
479 * return (fPaint). We then draw the primitive (using srcover) into a cleared
480 * buffer/surface.
481 * 3. Restore the layer created in #1
482 * The imagefilter is passed the buffer/surface from the layer (now filled with the
483 * src pixels of the primitive). It returns a new "filtered" buffer, which we
484 * draw onto the previous layer using the xfermode from the original paint.
485 */
reed@google.com8926b162012-03-23 15:36:36 +0000486 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500487 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700488 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700489 SkRect storage;
490 if (rawBounds) {
491 // Make rawBounds include all paint outsets except for those due to image filters.
492 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
493 }
reedbfd5f172016-01-07 11:28:08 -0800494 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700495 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700496 fTempLayerForImageFilter = true;
497 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000498 }
499
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000500 if (SkDrawLooper* looper = paint.getLooper()) {
herbbf6d80a2016-11-15 06:26:56 -0800501 fLooperContext = fLooperContextAllocator.createWithIniter(
502 looper->contextSize(),
503 [&](void* buffer) {
504 return looper->createContext(canvas, buffer);
505 });
reed@google.com129ec222012-05-15 13:24:09 +0000506 fIsSimple = false;
507 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700508 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000509 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700510 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000511 }
512 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000513
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700515 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000516 fCanvas->internalRestore();
517 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000518 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000520
reed@google.com4e2b3d32011-04-07 14:18:59 +0000521 const SkPaint& paint() const {
522 SkASSERT(fPaint);
523 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000525
reed@google.com129ec222012-05-15 13:24:09 +0000526 bool next(SkDrawFilter::Type drawType) {
527 if (fDone) {
528 return false;
529 } else if (fIsSimple) {
530 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000531 return !fPaint->nothingToDraw();
532 } else {
533 return this->doNext(drawType);
534 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000535 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000536
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537private:
reeddbc3cef2015-04-29 12:18:57 -0700538 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
539 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000540 SkCanvas* fCanvas;
541 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000542 SkDrawFilter* fFilter;
543 const SkPaint* fPaint;
544 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700545 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000546 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000547 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000548 SkDrawLooper::Context* fLooperContext;
549 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000550
551 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552};
553
reed@google.com129ec222012-05-15 13:24:09 +0000554bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700555 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000556 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700557 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000558
reeddbc3cef2015-04-29 12:18:57 -0700559 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
560 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000561
reed5c476fb2015-04-20 08:04:21 -0700562 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700563 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700564 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000565 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000566
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000567 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000568 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000569 return false;
570 }
571 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000572 if (!fFilter->filter(paint, drawType)) {
573 fDone = true;
574 return false;
575 }
halcanary96fcdcc2015-08-27 07:41:13 -0700576 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000577 // no looper means we only draw once
578 fDone = true;
579 }
580 }
581 fPaint = paint;
582
583 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000584 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000585 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000586 }
587
588 // call this after any possible paint modifiers
589 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700590 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000591 return false;
592 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000593 return true;
594}
595
reed@android.com8a1c16f2008-12-17 15:59:43 +0000596////////// macros to place around the internal draw calls //////////////////
597
reed3aafe112016-08-18 12:45:34 -0700598#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
599 this->predrawNotify(); \
600 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
601 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800602 SkDrawIter iter(this);
603
604
reed@google.com8926b162012-03-23 15:36:36 +0000605#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000606 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700607 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000608 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000609 SkDrawIter iter(this);
610
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000611#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000612 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700613 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000614 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000616
reedc83a2972015-07-16 07:40:45 -0700617#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
618 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700619 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700620 while (looper.next(type)) { \
621 SkDrawIter iter(this);
622
reed@google.com4e2b3d32011-04-07 14:18:59 +0000623#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624
625////////////////////////////////////////////////////////////////////////////
626
msarettfbfa2582016-08-12 08:29:08 -0700627static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
628 if (bounds.isEmpty()) {
629 return SkRect::MakeEmpty();
630 }
631
632 // Expand bounds out by 1 in case we are anti-aliasing. We store the
633 // bounds as floats to enable a faster quick reject implementation.
634 SkRect dst;
635 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
636 return dst;
637}
638
mtkleinfeaadee2015-04-08 11:25:48 -0700639void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
640 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700641 fClipStack->reset();
642 fMCRec->reset(bounds);
643
644 // We're peering through a lot of structs here. Only at this scope do we
645 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
646 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700647 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700648 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700649}
650
reedd9544982014-09-09 18:46:22 -0700651SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800652 if (device && device->forceConservativeRasterClip()) {
653 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
654 }
655 // Since init() is only called once by our constructors, it is safe to perform this
656 // const-cast.
657 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
658
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000659 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700660 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800661 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700662 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700663#ifdef SK_EXPERIMENTAL_SHADOWING
664 fLights = nullptr;
665#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666
halcanary385fe4d2015-08-26 13:07:48 -0700667 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700668
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700670 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500671 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700672 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000673
reeda499f902015-05-01 09:34:31 -0700674 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
675 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700676 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700677 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700678
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680
halcanary96fcdcc2015-08-27 07:41:13 -0700681 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000682
reedf92c8662014-08-18 08:02:43 -0700683 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700684 // The root device and the canvas should always have the same pixel geometry
685 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700686 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800687 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700688 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700689 }
msarettfbfa2582016-08-12 08:29:08 -0700690
reedf92c8662014-08-18 08:02:43 -0700691 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692}
693
reed@google.comcde92112011-07-06 20:00:52 +0000694SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000695 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700696 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800697 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000698{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000699 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000700
halcanary96fcdcc2015-08-27 07:41:13 -0700701 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000702}
703
reedd9544982014-09-09 18:46:22 -0700704static SkBitmap make_nopixels(int width, int height) {
705 SkBitmap bitmap;
706 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
707 return bitmap;
708}
709
710class SkNoPixelsBitmapDevice : public SkBitmapDevice {
711public:
robertphillipsfcf78292015-06-19 11:49:52 -0700712 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
713 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800714 {
715 this->setOrigin(bounds.x(), bounds.y());
716 }
reedd9544982014-09-09 18:46:22 -0700717
718private:
piotaixrb5fae932014-09-24 13:03:30 -0700719
reedd9544982014-09-09 18:46:22 -0700720 typedef SkBitmapDevice INHERITED;
721};
722
reed96a857e2015-01-25 10:33:58 -0800723SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000724 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800725 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800726 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000727{
728 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700729
halcanary385fe4d2015-08-26 13:07:48 -0700730 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
731 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700732}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000733
reed78e27682014-11-19 08:04:34 -0800734SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700735 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700736 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800737 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700738{
739 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700740
halcanary385fe4d2015-08-26 13:07:48 -0700741 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700742}
743
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000744SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000745 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700746 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800747 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000748{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700750
reedd9544982014-09-09 18:46:22 -0700751 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752}
753
robertphillipsfcf78292015-06-19 11:49:52 -0700754SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
755 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700756 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800757 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700758{
759 inc_canvas();
760
761 this->init(device, flags);
762}
763
reed4a8126e2014-09-22 07:29:03 -0700764SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700765 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700766 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800767 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700768{
769 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700770
Hal Canary704cd322016-11-07 14:13:52 -0500771 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
772 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700773}
reed29c857d2014-09-21 10:25:07 -0700774
Mike Reed356f7c22017-01-10 11:58:39 -0500775SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
776 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700777 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
778 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500779 , fAllocator(std::move(alloc))
reed42b73eb2015-11-20 13:42:42 -0800780 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700781{
782 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700783
Mike Reed356f7c22017-01-10 11:58:39 -0500784 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500785 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786}
787
Mike Reed356f7c22017-01-10 11:58:39 -0500788SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
789
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790SkCanvas::~SkCanvas() {
791 // free up the contents of our deque
792 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000793
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794 this->internalRestore(); // restore the last, since we're going away
795
halcanary385fe4d2015-08-26 13:07:48 -0700796 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000797
reed@android.com8a1c16f2008-12-17 15:59:43 +0000798 dec_canvas();
799}
800
fmalita53d9f1c2016-01-25 06:23:54 -0800801#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000802SkDrawFilter* SkCanvas::getDrawFilter() const {
803 return fMCRec->fFilter;
804}
805
806SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700807 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
809 return filter;
810}
fmalita77650002016-01-21 18:47:11 -0800811#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000813SkMetaData& SkCanvas::getMetaData() {
814 // metadata users are rare, so we lazily allocate it. If that changes we
815 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700816 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000817 fMetaData = new SkMetaData;
818 }
819 return *fMetaData;
820}
821
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822///////////////////////////////////////////////////////////////////////////////
823
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000824void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700825 this->onFlush();
826}
827
828void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000829 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000830 if (device) {
831 device->flush();
832 }
833}
834
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000835SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000836 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000837 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
838}
839
senorblancoafc7cce2016-02-02 18:44:15 -0800840SkIRect SkCanvas::getTopLayerBounds() const {
841 SkBaseDevice* d = this->getTopDevice();
842 if (!d) {
843 return SkIRect::MakeEmpty();
844 }
845 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
846}
847
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000848SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000849 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000850 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851 SkASSERT(rec && rec->fLayer);
852 return rec->fLayer->fDevice;
853}
854
Florin Malita0ed3b642017-01-13 16:56:38 +0000855SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000856 return fMCRec->fTopLayer->fDevice;
857}
858
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000859bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000860 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700861 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700862 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000863 return false;
864 }
865 weAllocated = true;
866 }
867
reedcf01e312015-05-23 19:14:51 -0700868 SkAutoPixmapUnlock unlocker;
869 if (bitmap->requestLock(&unlocker)) {
870 const SkPixmap& pm = unlocker.pixmap();
871 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
872 return true;
873 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000874 }
875
876 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500877 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000878 }
879 return false;
880}
reed@google.com51df9e32010-12-23 19:29:18 +0000881
bsalomon@google.comc6980972011-11-02 19:57:21 +0000882bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000883 SkIRect r = srcRect;
884 const SkISize size = this->getBaseLayerSize();
885 if (!r.intersect(0, 0, size.width(), size.height())) {
886 bitmap->reset();
887 return false;
888 }
889
reed84825042014-09-02 12:50:45 -0700890 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000891 // bitmap will already be reset.
892 return false;
893 }
894 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
895 bitmap->reset();
896 return false;
897 }
898 return true;
899}
900
reed96472de2014-12-10 09:53:42 -0800901bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000902 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000903 if (!device) {
904 return false;
905 }
mtkleinf0f14112014-12-12 08:46:25 -0800906
Matt Sarett03dd6d52017-01-23 12:15:09 -0500907 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000908}
909
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000910bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700911 SkAutoPixmapUnlock unlocker;
912 if (bitmap.requestLock(&unlocker)) {
913 const SkPixmap& pm = unlocker.pixmap();
914 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000915 }
916 return false;
917}
918
Matt Sarett03dd6d52017-01-23 12:15:09 -0500919bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000920 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000921 SkBaseDevice* device = this->getDevice();
922 if (!device) {
923 return false;
924 }
925
Matt Sarett03dd6d52017-01-23 12:15:09 -0500926 // This check gives us an early out and prevents generation ID churn on the surface.
927 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
928 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
929 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
930 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000931 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000932
Matt Sarett03dd6d52017-01-23 12:15:09 -0500933 // Tell our owning surface to bump its generation ID.
934 const bool completeOverwrite =
935 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700936 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700937
Matt Sarett03dd6d52017-01-23 12:15:09 -0500938 // This can still fail, most notably in the case of a invalid color type or alpha type
939 // conversion. We could pull those checks into this function and avoid the unnecessary
940 // generation ID bump. But then we would be performing those checks twice, since they
941 // are also necessary at the bitmap/pixmap entry points.
942 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000943}
reed@google.com51df9e32010-12-23 19:29:18 +0000944
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945//////////////////////////////////////////////////////////////////////////////
946
reed@android.com8a1c16f2008-12-17 15:59:43 +0000947void SkCanvas::updateDeviceCMCache() {
948 if (fDeviceCMDirty) {
949 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700950 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000951 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000952
halcanary96fcdcc2015-08-27 07:41:13 -0700953 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700954 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000956 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000957 do {
reedde6c5312016-09-02 12:10:07 -0700958 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700959 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960 }
961 fDeviceCMDirty = false;
962 }
963}
964
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965///////////////////////////////////////////////////////////////////////////////
966
reed2ff1fce2014-12-11 07:07:37 -0800967void SkCanvas::checkForDeferredSave() {
968 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800969 this->doSave();
970 }
971}
972
reedf0090cb2014-11-26 08:55:51 -0800973int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800974#ifdef SK_DEBUG
975 int count = 0;
976 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
977 for (;;) {
978 const MCRec* rec = (const MCRec*)iter.next();
979 if (!rec) {
980 break;
981 }
982 count += 1 + rec->fDeferredSaveCount;
983 }
984 SkASSERT(count == fSaveCount);
985#endif
986 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800987}
988
989int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800990 fSaveCount += 1;
991 fMCRec->fDeferredSaveCount += 1;
992 return this->getSaveCount() - 1; // return our prev value
993}
994
995void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800996 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700997
998 SkASSERT(fMCRec->fDeferredSaveCount > 0);
999 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001000 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001001}
1002
1003void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001004 if (fMCRec->fDeferredSaveCount > 0) {
1005 SkASSERT(fSaveCount > 1);
1006 fSaveCount -= 1;
1007 fMCRec->fDeferredSaveCount -= 1;
1008 } else {
1009 // check for underflow
1010 if (fMCStack.count() > 1) {
1011 this->willRestore();
1012 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001013 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001014 this->internalRestore();
1015 this->didRestore();
1016 }
reedf0090cb2014-11-26 08:55:51 -08001017 }
1018}
1019
1020void SkCanvas::restoreToCount(int count) {
1021 // sanity check
1022 if (count < 1) {
1023 count = 1;
1024 }
mtkleinf0f14112014-12-12 08:46:25 -08001025
reedf0090cb2014-11-26 08:55:51 -08001026 int n = this->getSaveCount() - count;
1027 for (int i = 0; i < n; ++i) {
1028 this->restore();
1029 }
1030}
1031
reed2ff1fce2014-12-11 07:07:37 -08001032void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001033 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001034 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001035 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001036
reed687fa1c2015-04-07 08:00:56 -07001037 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001038}
1039
reed4960eee2015-12-18 07:09:18 -08001040bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001041 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001042}
1043
reed4960eee2015-12-18 07:09:18 -08001044bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001045 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001046 SkIRect clipBounds = this->getDeviceClipBounds();
1047 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001048 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001049 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001050
reed96e657d2015-03-10 17:30:07 -07001051 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1052
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001053 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001054 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001055 if (bounds && !imageFilter->canComputeFastBounds()) {
1056 bounds = nullptr;
1057 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001058 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001059 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001060 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001061 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001062
reed96e657d2015-03-10 17:30:07 -07001063 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064 r.roundOut(&ir);
1065 // early exit if the layer's bounds are clipped out
1066 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001067 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001068 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001069 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001070 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001071 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072 }
1073 } else { // no user bounds, so just use the clip
1074 ir = clipBounds;
1075 }
reed180aec42015-03-11 10:39:04 -07001076 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001077
reed4960eee2015-12-18 07:09:18 -08001078 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001079 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001080 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001081 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001082 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001083 }
1084
1085 if (intersection) {
1086 *intersection = ir;
1087 }
1088 return true;
1089}
1090
reed4960eee2015-12-18 07:09:18 -08001091
reed4960eee2015-12-18 07:09:18 -08001092int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1093 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001094}
1095
reed70ee31b2015-12-10 13:44:45 -08001096int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001097 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1098}
1099
1100int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1101 SaveLayerRec rec(origRec);
1102 if (gIgnoreSaveLayerBounds) {
1103 rec.fBounds = nullptr;
1104 }
1105 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1106 fSaveCount += 1;
1107 this->internalSaveLayer(rec, strategy);
1108 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001109}
1110
reeda2217ef2016-07-20 06:04:34 -07001111void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1112 SkBaseDevice* dst, const SkMatrix& ctm,
1113 const SkClipStack* clipStack) {
1114 SkDraw draw;
1115 SkRasterClip rc;
1116 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1117 if (!dst->accessPixels(&draw.fDst)) {
1118 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001119 }
reeda2217ef2016-07-20 06:04:34 -07001120 draw.fMatrix = &SkMatrix::I();
1121 draw.fRC = &rc;
1122 draw.fClipStack = clipStack;
1123 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001124
1125 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001126 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001127
1128 int x = src->getOrigin().x() - dst->getOrigin().x();
1129 int y = src->getOrigin().y() - dst->getOrigin().y();
1130 auto special = src->snapSpecial();
1131 if (special) {
1132 dst->drawSpecial(draw, special.get(), x, y, p);
1133 }
robertphillips7354a4b2015-12-16 05:08:27 -08001134}
reed70ee31b2015-12-10 13:44:45 -08001135
reed129ed1c2016-02-22 06:42:31 -08001136static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1137 const SkPaint* paint) {
1138 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1139 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001140 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001141 const bool hasImageFilter = paint && paint->getImageFilter();
1142
1143 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1144 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1145 // force to L32
1146 return SkImageInfo::MakeN32(w, h, alphaType);
1147 } else {
1148 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001149 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001150 }
1151}
1152
reed4960eee2015-12-18 07:09:18 -08001153void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1154 const SkRect* bounds = rec.fBounds;
1155 const SkPaint* paint = rec.fPaint;
1156 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1157
reed8c30a812016-04-20 16:36:51 -07001158 SkLazyPaint lazyP;
1159 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1160 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001161 SkMatrix remainder;
1162 SkSize scale;
1163 /*
1164 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1165 * but they do handle scaling. To accommodate this, we do the following:
1166 *
1167 * 1. Stash off the current CTM
1168 * 2. Decompose the CTM into SCALE and REMAINDER
1169 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1170 * contains the REMAINDER
1171 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1172 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1173 * of the original imagefilter, and draw that (via drawSprite)
1174 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1175 *
1176 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1177 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1178 */
reed96a04f32016-04-25 09:25:15 -07001179 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001180 stashedMatrix.decomposeScale(&scale, &remainder))
1181 {
1182 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1183 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1184 SkPaint* p = lazyP.set(*paint);
1185 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1186 SkFilterQuality::kLow_SkFilterQuality,
1187 sk_ref_sp(imageFilter)));
1188 imageFilter = p->getImageFilter();
1189 paint = p;
1190 }
reed8c30a812016-04-20 16:36:51 -07001191
junov@chromium.orga907ac32012-02-24 21:54:07 +00001192 // do this before we create the layer. We don't call the public save() since
1193 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001194 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001195
1196 fDeviceCMDirty = true;
1197
1198 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001199 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001200 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201 }
1202
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001203 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1204 // the clipRectBounds() call above?
1205 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001206 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001207 }
1208
reed4960eee2015-12-18 07:09:18 -08001209 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001210 SkPixelGeometry geo = fProps.pixelGeometry();
1211 if (paint) {
reed76033be2015-03-14 10:54:31 -07001212 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001213 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001214 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001215 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001216 }
1217 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218
robertphillips5139e502016-07-19 05:10:40 -07001219 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001220 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001221 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001222 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001223 }
reedb2db8982014-11-13 12:41:02 -08001224
robertphillips5139e502016-07-19 05:10:40 -07001225 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001226 paint);
1227
Hal Canary704cd322016-11-07 14:13:52 -05001228 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001229 {
reed70ee31b2015-12-10 13:44:45 -08001230 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001231 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001232 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001233 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001234 preserveLCDText,
1235 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001236 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1237 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001238 return;
reed61f501f2015-04-29 08:34:00 -07001239 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001240 }
robertphillips5139e502016-07-19 05:10:40 -07001241 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001242
Hal Canary704cd322016-11-07 14:13:52 -05001243 DeviceCM* layer =
1244 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245
1246 layer->fNext = fMCRec->fTopLayer;
1247 fMCRec->fLayer = layer;
1248 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001249
1250 if (rec.fBackdrop) {
Hal Canary704cd322016-11-07 14:13:52 -05001251 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
reeda2217ef2016-07-20 06:04:34 -07001252 fMCRec->fMatrix, this->getClipStack());
1253 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001254}
1255
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001256int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001257 if (0xFF == alpha) {
1258 return this->saveLayer(bounds, nullptr);
1259 } else {
1260 SkPaint tmpPaint;
1261 tmpPaint.setAlpha(alpha);
1262 return this->saveLayer(bounds, &tmpPaint);
1263 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001264}
1265
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266void SkCanvas::internalRestore() {
1267 SkASSERT(fMCStack.count() != 0);
1268
1269 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270
reed687fa1c2015-04-07 08:00:56 -07001271 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001272
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001273 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274 DeviceCM* layer = fMCRec->fLayer; // may be null
1275 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001276 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277
1278 // now do the normal restore()
1279 fMCRec->~MCRec(); // balanced in save()
1280 fMCStack.pop_back();
1281 fMCRec = (MCRec*)fMCStack.back();
1282
1283 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1284 since if we're being recorded, we don't want to record this (the
1285 recorder will have already recorded the restore).
1286 */
bsalomon49f085d2014-09-05 13:34:00 -07001287 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001289 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001290 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001291 // restore what we smashed in internalSaveLayer
1292 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001293 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001295 delete layer;
reedb679ca82015-04-07 04:40:48 -07001296 } else {
1297 // we're at the root
reeda499f902015-05-01 09:34:31 -07001298 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001299 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001300 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001302 }
msarettfbfa2582016-08-12 08:29:08 -07001303
1304 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001305 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001306 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1307 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308}
1309
reede8f30622016-03-23 18:59:25 -07001310sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001311 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001312 props = &fProps;
1313 }
1314 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001315}
1316
reede8f30622016-03-23 18:59:25 -07001317sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001318 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001319 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001320}
1321
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001322SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001323 return this->onImageInfo();
1324}
1325
1326SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001327 SkBaseDevice* dev = this->getDevice();
1328 if (dev) {
1329 return dev->imageInfo();
1330 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001331 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001332 }
1333}
1334
brianosman898235c2016-04-06 07:38:23 -07001335bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001336 return this->onGetProps(props);
1337}
1338
1339bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001340 SkBaseDevice* dev = this->getDevice();
1341 if (dev) {
1342 if (props) {
1343 *props = fProps;
1344 }
1345 return true;
1346 } else {
1347 return false;
1348 }
1349}
1350
reed6ceeebd2016-03-09 14:26:26 -08001351bool SkCanvas::peekPixels(SkPixmap* pmap) {
1352 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001353}
1354
reed884e97c2015-05-26 11:31:54 -07001355bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001356 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001357 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001358}
1359
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001360void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001361 SkPixmap pmap;
1362 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001363 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001364 }
1365 if (info) {
1366 *info = pmap.info();
1367 }
1368 if (rowBytes) {
1369 *rowBytes = pmap.rowBytes();
1370 }
1371 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001372 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001373 }
reed884e97c2015-05-26 11:31:54 -07001374 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001375}
1376
reed884e97c2015-05-26 11:31:54 -07001377bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001378 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001379 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001380}
1381
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383
reed7503d602016-07-15 14:23:29 -07001384void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001386 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001387 paint = &tmp;
1388 }
reed@google.com4b226022011-01-11 18:32:13 +00001389
reed@google.com8926b162012-03-23 15:36:36 +00001390 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001391
reed@android.com8a1c16f2008-12-17 15:59:43 +00001392 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001393 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001394 paint = &looper.paint();
1395 SkImageFilter* filter = paint->getImageFilter();
1396 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001397 if (filter) {
1398 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1399 if (specialImage) {
1400 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1401 }
reed@google.com76dd2772012-01-05 21:15:07 +00001402 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001403 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001404 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001405 }
reeda2217ef2016-07-20 06:04:34 -07001406
reed@google.com4e2b3d32011-04-07 14:18:59 +00001407 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408}
1409
reed32704672015-12-16 08:27:10 -08001410/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001411
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001412void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001413 if (dx || dy) {
1414 this->checkForDeferredSave();
1415 fDeviceCMDirty = true;
1416 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001417
reedfe69b502016-09-12 06:31:48 -07001418 // Translate shouldn't affect the is-scale-translateness of the matrix.
1419 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001420
reedfe69b502016-09-12 06:31:48 -07001421 this->didTranslate(dx,dy);
1422 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423}
1424
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001425void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001426 SkMatrix m;
1427 m.setScale(sx, sy);
1428 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429}
1430
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001431void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001432 SkMatrix m;
1433 m.setRotate(degrees);
1434 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001435}
1436
bungeman7438bfc2016-07-12 15:01:19 -07001437void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1438 SkMatrix m;
1439 m.setRotate(degrees, px, py);
1440 this->concat(m);
1441}
1442
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001443void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001444 SkMatrix m;
1445 m.setSkew(sx, sy);
1446 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001447}
1448
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001449void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001450 if (matrix.isIdentity()) {
1451 return;
1452 }
1453
reed2ff1fce2014-12-11 07:07:37 -08001454 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001455 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001456 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001457 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001458 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001459}
1460
reed8c30a812016-04-20 16:36:51 -07001461void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001463 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001464 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001465}
1466
1467void SkCanvas::setMatrix(const SkMatrix& matrix) {
1468 this->checkForDeferredSave();
1469 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001470 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001471}
1472
reed@android.com8a1c16f2008-12-17 15:59:43 +00001473void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001474 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001475}
1476
vjiaoblack95302da2016-07-21 10:25:54 -07001477#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001478void SkCanvas::translateZ(SkScalar z) {
1479 this->checkForDeferredSave();
1480 this->fMCRec->fCurDrawDepth += z;
1481 this->didTranslateZ(z);
1482}
1483
1484SkScalar SkCanvas::getZ() const {
1485 return this->fMCRec->fCurDrawDepth;
1486}
1487
vjiaoblack95302da2016-07-21 10:25:54 -07001488void SkCanvas::setLights(sk_sp<SkLights> lights) {
1489 this->fLights = lights;
1490}
1491
1492sk_sp<SkLights> SkCanvas::getLights() const {
1493 return this->fLights;
1494}
1495#endif
1496
reed@android.com8a1c16f2008-12-17 15:59:43 +00001497//////////////////////////////////////////////////////////////////////////////
1498
Mike Reedc1f77742016-12-09 09:00:50 -05001499void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001500 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001501 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1502 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001503}
1504
Mike Reedc1f77742016-12-09 09:00:50 -05001505void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001506 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reedc64eff52015-11-21 12:39:45 -08001507 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001508 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1509 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1510 isAA);
reedc64eff52015-11-21 12:39:45 -08001511 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001512 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001513}
1514
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001515void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1516 fClipRestrictionRect = rect;
1517 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
1518 if (!fClipRestrictionRect.isEmpty()) {
1519 this->checkForDeferredSave();
1520 AutoValidateClip avc(this);
1521 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1522 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1523 fDeviceCMDirty = true;
1524 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1525 }
1526}
1527
Mike Reedc1f77742016-12-09 09:00:50 -05001528void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001529 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001530 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001531 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001532 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1533 } else {
1534 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001535 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001536}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001537
Mike Reedc1f77742016-12-09 09:00:50 -05001538void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001539 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001540
Brian Salomona3b45d42016-10-03 11:36:16 -04001541 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001542
Brian Salomona3b45d42016-10-03 11:36:16 -04001543 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1544 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1545 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1546 isAA);
1547 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1548 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001549}
1550
Mike Reedc1f77742016-12-09 09:00:50 -05001551void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001552 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001553 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001554
1555 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1556 SkRect r;
1557 if (path.isRect(&r)) {
1558 this->onClipRect(r, op, edgeStyle);
1559 return;
1560 }
1561 SkRRect rrect;
1562 if (path.isOval(&r)) {
1563 rrect.setOval(r);
1564 this->onClipRRect(rrect, op, edgeStyle);
1565 return;
1566 }
1567 if (path.isRRect(&rrect)) {
1568 this->onClipRRect(rrect, op, edgeStyle);
1569 return;
1570 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001571 }
robertphillips39f05382015-11-24 09:30:12 -08001572
1573 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001574}
1575
Mike Reedc1f77742016-12-09 09:00:50 -05001576void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001577 AutoValidateClip avc(this);
1578
reed@android.com8a1c16f2008-12-17 15:59:43 +00001579 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001580 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001581
Brian Salomona3b45d42016-10-03 11:36:16 -04001582 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001583
Brian Salomona3b45d42016-10-03 11:36:16 -04001584 const SkPath* rasterClipPath = &path;
1585 const SkMatrix* matrix = &fMCRec->fMatrix;
1586 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001587 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001588 isAA = getClipStack()->asPath(&tempPath);
1589 rasterClipPath = &tempPath;
1590 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001591 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001592 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001593 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1594 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001595 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001596}
1597
Mike Reedc1f77742016-12-09 09:00:50 -05001598void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001599 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001600 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001601}
1602
Mike Reedc1f77742016-12-09 09:00:50 -05001603void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001604 AutoValidateClip avc(this);
1605
reed@android.com8a1c16f2008-12-17 15:59:43 +00001606 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001607
reed@google.com5c3d1472011-02-22 19:12:23 +00001608 // todo: signal fClipStack that we have a region, and therefore (I guess)
1609 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001610 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001611
reed73603f32016-09-20 08:42:38 -07001612 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001613 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614}
1615
reed@google.com819c9212011-02-23 18:56:55 +00001616#ifdef SK_DEBUG
1617void SkCanvas::validateClip() const {
1618 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001619 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001620 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001621 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001622 return;
1623 }
1624
reed@google.com819c9212011-02-23 18:56:55 +00001625 SkIRect ir;
1626 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001627 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001628
reed687fa1c2015-04-07 08:00:56 -07001629 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001630 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001631 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001632 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001633 case SkClipStack::Element::kRect_Type:
1634 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001635 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001636 break;
1637 case SkClipStack::Element::kEmpty_Type:
1638 tmpClip.setEmpty();
1639 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001640 default: {
1641 SkPath path;
1642 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001643 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1644 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001645 break;
1646 }
reed@google.com819c9212011-02-23 18:56:55 +00001647 }
1648 }
reed@google.com819c9212011-02-23 18:56:55 +00001649}
1650#endif
1651
reed@google.com90c07ea2012-04-13 13:50:27 +00001652void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001653 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001654 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001655
halcanary96fcdcc2015-08-27 07:41:13 -07001656 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001657 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001658 }
1659}
1660
reed@google.com5c3d1472011-02-22 19:12:23 +00001661///////////////////////////////////////////////////////////////////////////////
1662
reed@google.com754de5f2014-02-24 19:38:20 +00001663bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001664 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001665}
1666
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001667bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001668 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001669}
1670
msarettfbfa2582016-08-12 08:29:08 -07001671static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1672#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1673 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1674 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1675 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1676 return 0xF != _mm_movemask_ps(mask);
1677#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1678 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1679 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1680 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1681 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1682#else
1683 SkRect devRectAsRect;
1684 SkRect devClipAsRect;
1685 devRect.store(&devRectAsRect.fLeft);
1686 devClip.store(&devClipAsRect.fLeft);
1687 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1688#endif
1689}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001690
msarettfbfa2582016-08-12 08:29:08 -07001691// It's important for this function to not be inlined. Otherwise the compiler will share code
1692// between the fast path and the slow path, resulting in two slow paths.
1693static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1694 const SkMatrix& matrix) {
1695 SkRect deviceRect;
1696 matrix.mapRect(&deviceRect, src);
1697 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1698}
1699
1700bool SkCanvas::quickReject(const SkRect& src) const {
1701#ifdef SK_DEBUG
1702 // Verify that fDeviceClipBounds are set properly.
1703 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001704 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001705 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001706 } else {
msarettfbfa2582016-08-12 08:29:08 -07001707 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001708 }
msarettfbfa2582016-08-12 08:29:08 -07001709
msarett9637ea92016-08-18 14:03:30 -07001710 // Verify that fIsScaleTranslate is set properly.
1711 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001712#endif
1713
msarett9637ea92016-08-18 14:03:30 -07001714 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001715 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1716 }
1717
1718 // We inline the implementation of mapScaleTranslate() for the fast path.
1719 float sx = fMCRec->fMatrix.getScaleX();
1720 float sy = fMCRec->fMatrix.getScaleY();
1721 float tx = fMCRec->fMatrix.getTranslateX();
1722 float ty = fMCRec->fMatrix.getTranslateY();
1723 Sk4f scale(sx, sy, sx, sy);
1724 Sk4f trans(tx, ty, tx, ty);
1725
1726 // Apply matrix.
1727 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1728
1729 // Make sure left < right, top < bottom.
1730 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1731 Sk4f min = Sk4f::Min(ltrb, rblt);
1732 Sk4f max = Sk4f::Max(ltrb, rblt);
1733 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1734 // ARM this sequence generates the fastest (a single instruction).
1735 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1736
1737 // Check if the device rect is NaN or outside the clip.
1738 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739}
1740
reed@google.com3b3e8952012-08-16 20:53:31 +00001741bool SkCanvas::quickReject(const SkPath& path) const {
1742 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001743}
1744
Mike Reed42e8c532017-01-23 14:09:13 -05001745SkRect SkCanvas::onGetLocalClipBounds() const {
1746 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001747 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001748 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001749 }
1750
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001751 SkMatrix inverse;
1752 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001753 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001754 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001755 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001756
Mike Reed42e8c532017-01-23 14:09:13 -05001757 SkRect bounds;
1758 SkRect r;
1759 // adjust it outwards in case we are antialiasing
1760 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001761
Mike Reed42e8c532017-01-23 14:09:13 -05001762 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1763 ibounds.fRight + inset, ibounds.fBottom + inset);
1764 inverse.mapRect(&bounds, r);
1765 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001766}
1767
Mike Reed42e8c532017-01-23 14:09:13 -05001768SkIRect SkCanvas::onGetDeviceClipBounds() const {
reed1f836ee2014-07-07 07:49:34 -07001769 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001770 if (clip.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001771 return SkIRect::MakeEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001772 }
Mike Reed42e8c532017-01-23 14:09:13 -05001773 return clip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001774}
1775
reed@android.com8a1c16f2008-12-17 15:59:43 +00001776const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001777 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001778}
1779
Mike Reed3726a4a2017-01-19 11:36:41 -05001780void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1781 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1782 if (this->getGrContext()) {
1783 SkPath path;
1784 this->getClipStack()->asPath(&path);
1785 SkISize size = this->getBaseLayerSize();
1786 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1787 } else {
1788 *rgn = fMCRec->fRasterClip.forceGetBW();
1789 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001790}
1791
Brian Osman11052242016-10-27 14:47:55 -04001792GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001793 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001794 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001795}
1796
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001797GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001798 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001799 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001800}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001801
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001802void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1803 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001804 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001805 if (outer.isEmpty()) {
1806 return;
1807 }
1808 if (inner.isEmpty()) {
1809 this->drawRRect(outer, paint);
1810 return;
1811 }
1812
1813 // We don't have this method (yet), but technically this is what we should
1814 // be able to assert...
1815 // SkASSERT(outer.contains(inner));
1816 //
1817 // For now at least check for containment of bounds
1818 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1819
1820 this->onDrawDRRect(outer, inner, paint);
1821}
1822
reed41af9662015-01-05 07:49:08 -08001823// These need to stop being virtual -- clients need to override the onDraw... versions
1824
1825void SkCanvas::drawPaint(const SkPaint& paint) {
1826 this->onDrawPaint(paint);
1827}
1828
1829void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1830 this->onDrawRect(r, paint);
1831}
1832
msarettdca352e2016-08-26 06:37:45 -07001833void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1834 if (region.isEmpty()) {
1835 return;
1836 }
1837
1838 if (region.isRect()) {
1839 return this->drawIRect(region.getBounds(), paint);
1840 }
1841
1842 this->onDrawRegion(region, paint);
1843}
1844
reed41af9662015-01-05 07:49:08 -08001845void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1846 this->onDrawOval(r, paint);
1847}
1848
1849void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1850 this->onDrawRRect(rrect, paint);
1851}
1852
1853void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1854 this->onDrawPoints(mode, count, pts, paint);
1855}
1856
1857void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001858 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001859 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reedfaba3712016-11-03 14:45:31 -04001860 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, bmode,
reed41af9662015-01-05 07:49:08 -08001861 indices, indexCount, paint);
1862}
1863
1864void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1865 this->onDrawPath(path, paint);
1866}
1867
reeda85d4d02015-05-06 12:56:48 -07001868void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001869 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001870 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001871}
1872
reede47829b2015-08-06 10:02:53 -07001873void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1874 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001875 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001876 if (dst.isEmpty() || src.isEmpty()) {
1877 return;
1878 }
1879 this->onDrawImageRect(image, &src, dst, paint, constraint);
1880}
reed41af9662015-01-05 07:49:08 -08001881
reed84984ef2015-07-17 07:09:43 -07001882void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1883 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001884 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001885 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001886}
1887
reede47829b2015-08-06 10:02:53 -07001888void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1889 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001890 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001891 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1892 constraint);
1893}
reede47829b2015-08-06 10:02:53 -07001894
reed4c21dc52015-06-25 12:32:03 -07001895void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1896 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001897 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001898 if (dst.isEmpty()) {
1899 return;
1900 }
msarett552bca92016-08-03 06:53:26 -07001901 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1902 this->onDrawImageNine(image, center, dst, paint);
1903 } else {
reede47829b2015-08-06 10:02:53 -07001904 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001905 }
reed4c21dc52015-06-25 12:32:03 -07001906}
1907
msarett16882062016-08-16 09:31:08 -07001908void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1909 const SkPaint* paint) {
1910 RETURN_ON_NULL(image);
1911 if (dst.isEmpty()) {
1912 return;
1913 }
msarett71df2d72016-09-30 12:41:42 -07001914
1915 SkIRect bounds;
1916 Lattice latticePlusBounds = lattice;
1917 if (!latticePlusBounds.fBounds) {
1918 bounds = SkIRect::MakeWH(image->width(), image->height());
1919 latticePlusBounds.fBounds = &bounds;
1920 }
1921
1922 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1923 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001924 } else {
1925 this->drawImageRect(image, dst, paint);
1926 }
1927}
1928
reed41af9662015-01-05 07:49:08 -08001929void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001930 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001931 return;
1932 }
reed41af9662015-01-05 07:49:08 -08001933 this->onDrawBitmap(bitmap, dx, dy, paint);
1934}
1935
reede47829b2015-08-06 10:02:53 -07001936void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001937 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001938 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001939 return;
1940 }
reede47829b2015-08-06 10:02:53 -07001941 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001942}
1943
reed84984ef2015-07-17 07:09:43 -07001944void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1945 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001946 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001947}
1948
reede47829b2015-08-06 10:02:53 -07001949void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1950 SrcRectConstraint constraint) {
1951 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1952 constraint);
1953}
reede47829b2015-08-06 10:02:53 -07001954
reed41af9662015-01-05 07:49:08 -08001955void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1956 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001957 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001958 return;
1959 }
msarett552bca92016-08-03 06:53:26 -07001960 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1961 this->onDrawBitmapNine(bitmap, center, dst, paint);
1962 } else {
reeda5517e22015-07-14 10:54:12 -07001963 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001964 }
reed41af9662015-01-05 07:49:08 -08001965}
1966
msarettc573a402016-08-02 08:05:56 -07001967void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1968 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001969 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001970 return;
1971 }
msarett71df2d72016-09-30 12:41:42 -07001972
1973 SkIRect bounds;
1974 Lattice latticePlusBounds = lattice;
1975 if (!latticePlusBounds.fBounds) {
1976 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1977 latticePlusBounds.fBounds = &bounds;
1978 }
1979
1980 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1981 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001982 } else {
msarett16882062016-08-16 09:31:08 -07001983 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001984 }
msarettc573a402016-08-02 08:05:56 -07001985}
1986
reed71c3c762015-06-24 10:29:17 -07001987void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001988 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001989 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001990 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001991 if (count <= 0) {
1992 return;
1993 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001994 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001995 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001996 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001997}
1998
reedf70b5312016-03-04 16:36:20 -08001999void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2000 if (key) {
2001 this->onDrawAnnotation(rect, key, value);
2002 }
2003}
2004
reede47829b2015-08-06 10:02:53 -07002005void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2006 const SkPaint* paint, SrcRectConstraint constraint) {
2007 if (src) {
2008 this->drawImageRect(image, *src, dst, paint, constraint);
2009 } else {
2010 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2011 dst, paint, constraint);
2012 }
2013}
2014void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2015 const SkPaint* paint, SrcRectConstraint constraint) {
2016 if (src) {
2017 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2018 } else {
2019 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2020 dst, paint, constraint);
2021 }
2022}
2023
tomhudsoncb3bd182016-05-18 07:24:16 -07002024void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2025 SkIRect layer_bounds = this->getTopLayerBounds();
2026 if (matrix) {
2027 *matrix = this->getTotalMatrix();
2028 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2029 }
2030 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002031 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002032 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2033 }
2034}
2035
reed@android.com8a1c16f2008-12-17 15:59:43 +00002036//////////////////////////////////////////////////////////////////////////////
2037// These are the virtual drawing methods
2038//////////////////////////////////////////////////////////////////////////////
2039
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002040void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002041 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002042 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2043 }
2044}
2045
reed41af9662015-01-05 07:49:08 -08002046void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002047 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002048 this->internalDrawPaint(paint);
2049}
2050
2051void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002052 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002053
2054 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002055 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002056 }
2057
reed@google.com4e2b3d32011-04-07 14:18:59 +00002058 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002059}
2060
reed41af9662015-01-05 07:49:08 -08002061void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2062 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002063 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002064 if ((long)count <= 0) {
2065 return;
2066 }
2067
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002068 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002069 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002070 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002071 // special-case 2 points (common for drawing a single line)
2072 if (2 == count) {
2073 r.set(pts[0], pts[1]);
2074 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002075 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002076 }
senorblanco87e066e2015-10-28 11:23:36 -07002077 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2078 return;
2079 }
2080 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002081 }
reed@google.coma584aed2012-05-16 14:06:02 +00002082
halcanary96fcdcc2015-08-27 07:41:13 -07002083 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002084
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002085 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002086
reed@android.com8a1c16f2008-12-17 15:59:43 +00002087 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002088 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002089 }
reed@google.com4b226022011-01-11 18:32:13 +00002090
reed@google.com4e2b3d32011-04-07 14:18:59 +00002091 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002092}
2093
reed4a167172016-08-18 17:15:25 -07002094static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2095 return ((intptr_t)paint.getImageFilter() |
2096#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2097 (intptr_t)canvas->getDrawFilter() |
2098#endif
2099 (intptr_t)paint.getLooper() ) != 0;
2100}
2101
reed41af9662015-01-05 07:49:08 -08002102void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002103 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002104 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002105 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002106 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002107 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2108 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2109 SkRect tmp(r);
2110 tmp.sort();
2111
senorblanco87e066e2015-10-28 11:23:36 -07002112 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2113 return;
2114 }
2115 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002116 }
reed@google.com4b226022011-01-11 18:32:13 +00002117
reed4a167172016-08-18 17:15:25 -07002118 if (needs_autodrawlooper(this, paint)) {
2119 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002120
reed4a167172016-08-18 17:15:25 -07002121 while (iter.next()) {
2122 iter.fDevice->drawRect(iter, r, looper.paint());
2123 }
2124
2125 LOOPER_END
2126 } else {
2127 this->predrawNotify(bounds, &paint, false);
2128 SkDrawIter iter(this);
2129 while (iter.next()) {
2130 iter.fDevice->drawRect(iter, r, paint);
2131 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002132 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002133}
2134
msarett44df6512016-08-25 13:54:30 -07002135void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2136 SkRect storage;
2137 SkRect regionRect = SkRect::Make(region.getBounds());
2138 const SkRect* bounds = nullptr;
2139 if (paint.canComputeFastBounds()) {
2140 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2141 return;
2142 }
2143 bounds = &regionRect;
2144 }
2145
2146 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2147
2148 while (iter.next()) {
2149 iter.fDevice->drawRegion(iter, region, looper.paint());
2150 }
2151
2152 LOOPER_END
2153}
2154
reed41af9662015-01-05 07:49:08 -08002155void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002156 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002157 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002158 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002159 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002160 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2161 return;
2162 }
2163 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002164 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002165
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002166 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002167
2168 while (iter.next()) {
2169 iter.fDevice->drawOval(iter, oval, looper.paint());
2170 }
2171
2172 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002173}
2174
bsalomonac3aa242016-08-19 11:25:19 -07002175void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2176 SkScalar sweepAngle, bool useCenter,
2177 const SkPaint& paint) {
2178 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2179 const SkRect* bounds = nullptr;
2180 if (paint.canComputeFastBounds()) {
2181 SkRect storage;
2182 // Note we're using the entire oval as the bounds.
2183 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2184 return;
2185 }
2186 bounds = &oval;
2187 }
2188
2189 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2190
2191 while (iter.next()) {
2192 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2193 }
2194
2195 LOOPER_END
2196}
2197
reed41af9662015-01-05 07:49:08 -08002198void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002199 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002200 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002201 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002202 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002203 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2204 return;
2205 }
2206 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002207 }
2208
2209 if (rrect.isRect()) {
2210 // call the non-virtual version
2211 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002212 return;
2213 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002214 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002215 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2216 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002217 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002218
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002219 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002220
2221 while (iter.next()) {
2222 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2223 }
2224
2225 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002226}
2227
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002228void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2229 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002230 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002231 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002232 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002233 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2234 return;
2235 }
2236 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002237 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002238
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002239 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002240
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002241 while (iter.next()) {
2242 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2243 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002244
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002245 LOOPER_END
2246}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002247
reed41af9662015-01-05 07:49:08 -08002248void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002249 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002250 if (!path.isFinite()) {
2251 return;
2252 }
2253
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002254 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002255 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002256 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002257 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002258 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2259 return;
2260 }
2261 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002262 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002263
2264 const SkRect& r = path.getBounds();
2265 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002266 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002267 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002268 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002269 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002271
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002272 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002273
2274 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002275 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002276 }
2277
reed@google.com4e2b3d32011-04-07 14:18:59 +00002278 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002279}
2280
reed262a71b2015-12-05 13:07:27 -08002281bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002282 if (!paint.getImageFilter()) {
2283 return false;
2284 }
2285
2286 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002287 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002288 return false;
2289 }
2290
2291 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2292 // Once we can filter and the filter will return a result larger than itself, we should be
2293 // able to remove this constraint.
2294 // skbug.com/4526
2295 //
2296 SkPoint pt;
2297 ctm.mapXY(x, y, &pt);
2298 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2299 return ir.contains(fMCRec->fRasterClip.getBounds());
2300}
2301
reeda85d4d02015-05-06 12:56:48 -07002302void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002303 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002304 SkRect bounds = SkRect::MakeXYWH(x, y,
2305 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002306 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002307 SkRect tmp = bounds;
2308 if (paint) {
2309 paint->computeFastBounds(tmp, &tmp);
2310 }
2311 if (this->quickReject(tmp)) {
2312 return;
2313 }
reeda85d4d02015-05-06 12:56:48 -07002314 }
halcanary9d524f22016-03-29 09:03:52 -07002315
reeda85d4d02015-05-06 12:56:48 -07002316 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002317 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002318 paint = lazy.init();
2319 }
reed262a71b2015-12-05 13:07:27 -08002320
reeda2217ef2016-07-20 06:04:34 -07002321 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002322 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2323 *paint);
2324 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002325 special = this->getDevice()->makeSpecial(image);
2326 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002327 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002328 }
2329 }
2330
reed262a71b2015-12-05 13:07:27 -08002331 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2332
reeda85d4d02015-05-06 12:56:48 -07002333 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002334 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002335 if (special) {
2336 SkPoint pt;
2337 iter.fMatrix->mapXY(x, y, &pt);
2338 iter.fDevice->drawSpecial(iter, special.get(),
2339 SkScalarRoundToInt(pt.fX),
2340 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002341 } else {
2342 iter.fDevice->drawImage(iter, image, x, y, pnt);
2343 }
reeda85d4d02015-05-06 12:56:48 -07002344 }
halcanary9d524f22016-03-29 09:03:52 -07002345
reeda85d4d02015-05-06 12:56:48 -07002346 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002347}
2348
reed41af9662015-01-05 07:49:08 -08002349void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002350 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002351 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002352 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002353 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002354 if (paint) {
2355 paint->computeFastBounds(dst, &storage);
2356 }
2357 if (this->quickReject(storage)) {
2358 return;
2359 }
reeda85d4d02015-05-06 12:56:48 -07002360 }
2361 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002362 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002363 paint = lazy.init();
2364 }
halcanary9d524f22016-03-29 09:03:52 -07002365
senorblancoc41e7e12015-12-07 12:51:30 -08002366 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002367 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002368
reeda85d4d02015-05-06 12:56:48 -07002369 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002370 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002371 }
halcanary9d524f22016-03-29 09:03:52 -07002372
reeda85d4d02015-05-06 12:56:48 -07002373 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002374}
2375
reed41af9662015-01-05 07:49:08 -08002376void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002377 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002378 SkDEBUGCODE(bitmap.validate();)
2379
reed33366972015-10-08 09:22:02 -07002380 if (bitmap.drawsNothing()) {
2381 return;
2382 }
2383
2384 SkLazyPaint lazy;
2385 if (nullptr == paint) {
2386 paint = lazy.init();
2387 }
2388
2389 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2390
2391 SkRect storage;
2392 const SkRect* bounds = nullptr;
2393 if (paint->canComputeFastBounds()) {
2394 bitmap.getBounds(&storage);
2395 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002396 SkRect tmp = storage;
2397 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2398 return;
2399 }
2400 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002401 }
reed@google.com4b226022011-01-11 18:32:13 +00002402
reeda2217ef2016-07-20 06:04:34 -07002403 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002404 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2405 *paint);
2406 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002407 special = this->getDevice()->makeSpecial(bitmap);
2408 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002409 drawAsSprite = false;
2410 }
2411 }
2412
reed262a71b2015-12-05 13:07:27 -08002413 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002414
2415 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002416 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002417 if (special) {
reed262a71b2015-12-05 13:07:27 -08002418 SkPoint pt;
2419 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002420 iter.fDevice->drawSpecial(iter, special.get(),
2421 SkScalarRoundToInt(pt.fX),
2422 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002423 } else {
2424 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2425 }
reed33366972015-10-08 09:22:02 -07002426 }
msarettfbfa2582016-08-12 08:29:08 -07002427
reed33366972015-10-08 09:22:02 -07002428 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002429}
2430
reed@google.com9987ec32011-09-07 11:57:52 +00002431// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002432void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002433 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002434 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002435 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002436 return;
2437 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002438
halcanary96fcdcc2015-08-27 07:41:13 -07002439 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002440 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002441 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2442 return;
2443 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002444 }
reed@google.com3d608122011-11-21 15:16:16 +00002445
reed@google.com33535f32012-09-25 15:37:50 +00002446 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002447 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002448 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002449 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002450
senorblancoc41e7e12015-12-07 12:51:30 -08002451 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002452 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002453
reed@google.com33535f32012-09-25 15:37:50 +00002454 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002455 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002456 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002457
reed@google.com33535f32012-09-25 15:37:50 +00002458 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459}
2460
reed41af9662015-01-05 07:49:08 -08002461void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002462 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002463 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002464 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002465 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002466}
2467
reed4c21dc52015-06-25 12:32:03 -07002468void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2469 const SkPaint* paint) {
2470 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002471
halcanary96fcdcc2015-08-27 07:41:13 -07002472 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002473 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002474 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2475 return;
2476 }
reed@google.com3d608122011-11-21 15:16:16 +00002477 }
halcanary9d524f22016-03-29 09:03:52 -07002478
reed4c21dc52015-06-25 12:32:03 -07002479 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002480 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002481 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002482 }
halcanary9d524f22016-03-29 09:03:52 -07002483
senorblancoc41e7e12015-12-07 12:51:30 -08002484 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002485
reed4c21dc52015-06-25 12:32:03 -07002486 while (iter.next()) {
2487 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002488 }
halcanary9d524f22016-03-29 09:03:52 -07002489
reed4c21dc52015-06-25 12:32:03 -07002490 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002491}
2492
reed41af9662015-01-05 07:49:08 -08002493void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2494 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002495 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002496 SkDEBUGCODE(bitmap.validate();)
2497
halcanary96fcdcc2015-08-27 07:41:13 -07002498 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002499 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002500 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2501 return;
2502 }
reed4c21dc52015-06-25 12:32:03 -07002503 }
halcanary9d524f22016-03-29 09:03:52 -07002504
reed4c21dc52015-06-25 12:32:03 -07002505 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002506 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002507 paint = lazy.init();
2508 }
halcanary9d524f22016-03-29 09:03:52 -07002509
senorblancoc41e7e12015-12-07 12:51:30 -08002510 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002511
reed4c21dc52015-06-25 12:32:03 -07002512 while (iter.next()) {
2513 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2514 }
halcanary9d524f22016-03-29 09:03:52 -07002515
reed4c21dc52015-06-25 12:32:03 -07002516 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002517}
2518
msarett16882062016-08-16 09:31:08 -07002519void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2520 const SkPaint* paint) {
2521 if (nullptr == paint || paint->canComputeFastBounds()) {
2522 SkRect storage;
2523 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2524 return;
2525 }
2526 }
2527
2528 SkLazyPaint lazy;
2529 if (nullptr == paint) {
2530 paint = lazy.init();
2531 }
2532
2533 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2534
2535 while (iter.next()) {
2536 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2537 }
2538
2539 LOOPER_END
2540}
2541
2542void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2543 const SkRect& dst, const SkPaint* paint) {
2544 if (nullptr == paint || paint->canComputeFastBounds()) {
2545 SkRect storage;
2546 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2547 return;
2548 }
2549 }
2550
2551 SkLazyPaint lazy;
2552 if (nullptr == paint) {
2553 paint = lazy.init();
2554 }
2555
2556 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2557
2558 while (iter.next()) {
2559 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2560 }
2561
2562 LOOPER_END
2563}
2564
reed@google.comf67e4cf2011-03-15 20:56:58 +00002565class SkDeviceFilteredPaint {
2566public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002567 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002568 uint32_t filteredFlags = device->filterTextFlags(paint);
2569 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002570 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002571 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002572 fPaint = newPaint;
2573 } else {
2574 fPaint = &paint;
2575 }
2576 }
2577
reed@google.comf67e4cf2011-03-15 20:56:58 +00002578 const SkPaint& paint() const { return *fPaint; }
2579
2580private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002581 const SkPaint* fPaint;
2582 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002583};
2584
bungeman@google.com52c748b2011-08-22 21:30:43 +00002585void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2586 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002587 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002588 draw.fDevice->drawRect(draw, r, paint);
2589 } else {
2590 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002591 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002592 draw.fDevice->drawRect(draw, r, p);
2593 }
2594}
2595
2596void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2597 const char text[], size_t byteLength,
2598 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002599 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002600
2601 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002602 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002603 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002604 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002605 return;
2606 }
2607
2608 SkScalar width = 0;
2609 SkPoint start;
2610
2611 start.set(0, 0); // to avoid warning
2612 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2613 SkPaint::kStrikeThruText_Flag)) {
2614 width = paint.measureText(text, byteLength);
2615
2616 SkScalar offsetX = 0;
2617 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2618 offsetX = SkScalarHalf(width);
2619 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2620 offsetX = width;
2621 }
2622 start.set(x - offsetX, y);
2623 }
2624
2625 if (0 == width) {
2626 return;
2627 }
2628
2629 uint32_t flags = paint.getFlags();
2630
2631 if (flags & (SkPaint::kUnderlineText_Flag |
2632 SkPaint::kStrikeThruText_Flag)) {
2633 SkScalar textSize = paint.getTextSize();
2634 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2635 SkRect r;
2636
2637 r.fLeft = start.fX;
2638 r.fRight = start.fX + width;
2639
2640 if (flags & SkPaint::kUnderlineText_Flag) {
2641 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2642 start.fY);
2643 r.fTop = offset;
2644 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002645 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002646 }
2647 if (flags & SkPaint::kStrikeThruText_Flag) {
2648 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2649 start.fY);
2650 r.fTop = offset;
2651 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002652 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002653 }
2654 }
2655}
2656
reed@google.come0d9ce82014-04-23 04:00:17 +00002657void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2658 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002659 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002660
2661 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002662 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002663 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002664 DrawTextDecorations(iter, dfp.paint(),
2665 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002666 }
2667
reed@google.com4e2b3d32011-04-07 14:18:59 +00002668 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002669}
2670
reed@google.come0d9ce82014-04-23 04:00:17 +00002671void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2672 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002673 SkPoint textOffset = SkPoint::Make(0, 0);
2674
halcanary96fcdcc2015-08-27 07:41:13 -07002675 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002676
reed@android.com8a1c16f2008-12-17 15:59:43 +00002677 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002678 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002679 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002680 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002681 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002682
reed@google.com4e2b3d32011-04-07 14:18:59 +00002683 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002684}
2685
reed@google.come0d9ce82014-04-23 04:00:17 +00002686void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2687 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002688
2689 SkPoint textOffset = SkPoint::Make(0, constY);
2690
halcanary96fcdcc2015-08-27 07:41:13 -07002691 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002692
reed@android.com8a1c16f2008-12-17 15:59:43 +00002693 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002694 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002695 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002696 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002698
reed@google.com4e2b3d32011-04-07 14:18:59 +00002699 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002700}
2701
reed@google.come0d9ce82014-04-23 04:00:17 +00002702void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2703 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002704 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002705
reed@android.com8a1c16f2008-12-17 15:59:43 +00002706 while (iter.next()) {
2707 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002708 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002709 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002710
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002711 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002712}
2713
reed45561a02016-07-07 12:47:17 -07002714void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2715 const SkRect* cullRect, const SkPaint& paint) {
2716 if (cullRect && this->quickReject(*cullRect)) {
2717 return;
2718 }
2719
2720 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2721
2722 while (iter.next()) {
2723 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2724 }
2725
2726 LOOPER_END
2727}
2728
fmalita00d5c2c2014-08-21 08:53:26 -07002729void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2730 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002731
fmalita85d5eb92015-03-04 11:20:12 -08002732 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002733 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002734 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002735 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002736 SkRect tmp;
2737 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2738 return;
2739 }
2740 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002741 }
2742
fmalita024f9962015-03-03 19:08:17 -08002743 // We cannot filter in the looper as we normally do, because the paint is
2744 // incomplete at this point (text-related attributes are embedded within blob run paints).
2745 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002746 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002747
fmalita85d5eb92015-03-04 11:20:12 -08002748 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002749
fmalitaaa1b9122014-08-28 14:32:24 -07002750 while (iter.next()) {
2751 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002752 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002753 }
2754
fmalitaaa1b9122014-08-28 14:32:24 -07002755 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002756
2757 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002758}
2759
reed@google.come0d9ce82014-04-23 04:00:17 +00002760// These will become non-virtual, so they always call the (virtual) onDraw... method
2761void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2762 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002763 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002764 if (byteLength) {
2765 this->onDrawText(text, byteLength, x, y, paint);
2766 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002767}
2768void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2769 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002770 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002771 if (byteLength) {
2772 this->onDrawPosText(text, byteLength, pos, paint);
2773 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002774}
2775void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2776 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002777 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002778 if (byteLength) {
2779 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2780 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002781}
2782void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2783 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002784 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002785 if (byteLength) {
2786 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2787 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002788}
reed45561a02016-07-07 12:47:17 -07002789void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2790 const SkRect* cullRect, const SkPaint& paint) {
2791 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2792 if (byteLength) {
2793 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2794 }
2795}
fmalita00d5c2c2014-08-21 08:53:26 -07002796void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2797 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002798 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002799 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002800 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002801}
reed@google.come0d9ce82014-04-23 04:00:17 +00002802
reed41af9662015-01-05 07:49:08 -08002803void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2804 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002805 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002806 const uint16_t indices[], int indexCount,
2807 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002808 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002809 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002810
reed@android.com8a1c16f2008-12-17 15:59:43 +00002811 while (iter.next()) {
2812 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002813 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002814 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002815 }
reed@google.com4b226022011-01-11 18:32:13 +00002816
reed@google.com4e2b3d32011-04-07 14:18:59 +00002817 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002818}
2819
dandovb3c9d1c2014-08-12 08:34:29 -07002820void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002821 const SkPoint texCoords[4], SkBlendMode bmode,
2822 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002823 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002824 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002825 return;
2826 }
mtklein6cfa73a2014-08-13 13:33:49 -07002827
Mike Reedfaba3712016-11-03 14:45:31 -04002828 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002829}
2830
2831void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002832 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002833 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002834 // Since a patch is always within the convex hull of the control points, we discard it when its
2835 // bounding rectangle is completely outside the current clip.
2836 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002837 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002838 if (this->quickReject(bounds)) {
2839 return;
2840 }
mtklein6cfa73a2014-08-13 13:33:49 -07002841
halcanary96fcdcc2015-08-27 07:41:13 -07002842 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002843
dandovecfff212014-08-04 10:02:00 -07002844 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002845 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002846 }
mtklein6cfa73a2014-08-13 13:33:49 -07002847
dandovecfff212014-08-04 10:02:00 -07002848 LOOPER_END
2849}
2850
reeda8db7282015-07-07 10:22:31 -07002851void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002852 RETURN_ON_NULL(dr);
2853 if (x || y) {
2854 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2855 this->onDrawDrawable(dr, &matrix);
2856 } else {
2857 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002858 }
2859}
2860
reeda8db7282015-07-07 10:22:31 -07002861void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002862 RETURN_ON_NULL(dr);
2863 if (matrix && matrix->isIdentity()) {
2864 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002865 }
reede3b38ce2016-01-08 09:18:44 -08002866 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002867}
2868
2869void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002870 // drawable bounds are no longer reliable (e.g. android displaylist)
2871 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002872 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002873}
2874
reed71c3c762015-06-24 10:29:17 -07002875void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002876 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002877 const SkRect* cull, const SkPaint* paint) {
2878 if (cull && this->quickReject(*cull)) {
2879 return;
2880 }
2881
2882 SkPaint pnt;
2883 if (paint) {
2884 pnt = *paint;
2885 }
halcanary9d524f22016-03-29 09:03:52 -07002886
halcanary96fcdcc2015-08-27 07:41:13 -07002887 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002888 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002889 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002890 }
2891 LOOPER_END
2892}
2893
reedf70b5312016-03-04 16:36:20 -08002894void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2895 SkASSERT(key);
2896
2897 SkPaint paint;
2898 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2899 while (iter.next()) {
2900 iter.fDevice->drawAnnotation(iter, rect, key, value);
2901 }
2902 LOOPER_END
2903}
2904
reed@android.com8a1c16f2008-12-17 15:59:43 +00002905//////////////////////////////////////////////////////////////////////////////
2906// These methods are NOT virtual, and therefore must call back into virtual
2907// methods, rather than actually drawing themselves.
2908//////////////////////////////////////////////////////////////////////////////
2909
reed374772b2016-10-05 17:33:02 -07002910void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002911 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002912 SkPaint paint;
2913
2914 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002915 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002916 this->drawPaint(paint);
2917}
2918
reed374772b2016-10-05 17:33:02 -07002919void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002920 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002921 SkPaint paint;
2922
2923 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002924 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002925 this->drawPaint(paint);
2926}
2927
2928void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002929 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002930 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002931
reed@android.com8a1c16f2008-12-17 15:59:43 +00002932 pt.set(x, y);
2933 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2934}
2935
2936void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002937 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002938 SkPoint pt;
2939 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002940
reed@android.com8a1c16f2008-12-17 15:59:43 +00002941 pt.set(x, y);
2942 paint.setColor(color);
2943 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2944}
2945
2946void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2947 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002948 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002949 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002950
reed@android.com8a1c16f2008-12-17 15:59:43 +00002951 pts[0].set(x0, y0);
2952 pts[1].set(x1, y1);
2953 this->drawPoints(kLines_PointMode, 2, pts, paint);
2954}
2955
2956void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2957 SkScalar right, SkScalar bottom,
2958 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002959 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002960 SkRect r;
2961
2962 r.set(left, top, right, bottom);
2963 this->drawRect(r, paint);
2964}
2965
2966void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2967 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002968 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002969 if (radius < 0) {
2970 radius = 0;
2971 }
2972
2973 SkRect r;
2974 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002975 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002976}
2977
2978void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2979 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002980 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002981 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002982 SkRRect rrect;
2983 rrect.setRectXY(r, rx, ry);
2984 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002985 } else {
2986 this->drawRect(r, paint);
2987 }
2988}
2989
reed@android.com8a1c16f2008-12-17 15:59:43 +00002990void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2991 SkScalar sweepAngle, bool useCenter,
2992 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002993 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002994 if (oval.isEmpty() || !sweepAngle) {
2995 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002996 }
bsalomon21af9ca2016-08-25 12:29:23 -07002997 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002998}
2999
3000void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3001 const SkPath& path, SkScalar hOffset,
3002 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003003 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003004 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003005
reed@android.com8a1c16f2008-12-17 15:59:43 +00003006 matrix.setTranslate(hOffset, vOffset);
3007 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3008}
3009
reed@android.comf76bacf2009-05-13 14:00:33 +00003010///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003011
3012/**
3013 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3014 * against the playback cost of recursing into the subpicture to get at its actual ops.
3015 *
3016 * For now we pick a conservatively small value, though measurement (and other heuristics like
3017 * the type of ops contained) may justify changing this value.
3018 */
3019#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003020
reedd5fa1a42014-08-09 11:08:05 -07003021void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003022 RETURN_ON_NULL(picture);
3023
reed1c2c4412015-04-30 13:09:24 -07003024 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003025 if (matrix && matrix->isIdentity()) {
3026 matrix = nullptr;
3027 }
3028 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3029 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3030 picture->playback(this);
3031 } else {
3032 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003033 }
3034}
robertphillips9b14f262014-06-04 05:40:44 -07003035
reedd5fa1a42014-08-09 11:08:05 -07003036void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3037 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003038 if (!paint || paint->canComputeFastBounds()) {
3039 SkRect bounds = picture->cullRect();
3040 if (paint) {
3041 paint->computeFastBounds(bounds, &bounds);
3042 }
3043 if (matrix) {
3044 matrix->mapRect(&bounds);
3045 }
3046 if (this->quickReject(bounds)) {
3047 return;
3048 }
3049 }
3050
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003051 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003052 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003053}
3054
vjiaoblack95302da2016-07-21 10:25:54 -07003055#ifdef SK_EXPERIMENTAL_SHADOWING
3056void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3057 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003058 const SkPaint* paint,
3059 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003060 RETURN_ON_NULL(picture);
3061
3062 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3063
vjiaoblacke6f5d562016-08-25 06:30:23 -07003064 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003065}
3066
3067void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3068 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003069 const SkPaint* paint,
3070 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003071 if (!paint || paint->canComputeFastBounds()) {
3072 SkRect bounds = picture->cullRect();
3073 if (paint) {
3074 paint->computeFastBounds(bounds, &bounds);
3075 }
3076 if (matrix) {
3077 matrix->mapRect(&bounds);
3078 }
3079 if (this->quickReject(bounds)) {
3080 return;
3081 }
3082 }
3083
3084 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3085
vjiaoblacke6f5d562016-08-25 06:30:23 -07003086 sk_sp<SkImage> povDepthMap;
3087 sk_sp<SkImage> diffuseMap;
3088
vjiaoblack904527d2016-08-09 09:32:09 -07003089 // povDepthMap
3090 {
3091 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003092 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3093 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003094 sk_sp<SkLights> povLight = builder.finish();
3095
3096 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3097 picture->cullRect().height(),
3098 kBGRA_8888_SkColorType,
3099 kOpaque_SkAlphaType);
3100
3101 // Create a new surface (that matches the backend of canvas)
3102 // to create the povDepthMap
3103 sk_sp<SkSurface> surf(this->makeSurface(info));
3104
3105 // Wrap another SPFCanvas around the surface
3106 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3107 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3108
3109 // set the depth map canvas to have the light as the user's POV
3110 depthMapCanvas->setLights(std::move(povLight));
3111
3112 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003113 povDepthMap = surf->makeImageSnapshot();
3114 }
3115
3116 // diffuseMap
3117 {
3118 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3119 picture->cullRect().height(),
3120 kBGRA_8888_SkColorType,
3121 kOpaque_SkAlphaType);
3122
3123 sk_sp<SkSurface> surf(this->makeSurface(info));
3124 surf->getCanvas()->drawPicture(picture);
3125
3126 diffuseMap = surf->makeImageSnapshot();
3127 }
vjiaoblack904527d2016-08-09 09:32:09 -07003128
3129 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3130 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003131 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3132 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003133
3134 // TODO: pass the depth to the shader in vertices, or uniforms
3135 // so we don't have to render depth and color separately
3136 for (int i = 0; i < fLights->numLights(); ++i) {
3137 // skip over ambient lights; they don't cast shadows
3138 // lights that have shadow maps do not need updating (because lights are immutable)
3139 sk_sp<SkImage> depthMap;
3140 SkISize shMapSize;
3141
3142 if (fLights->light(i).getShadowMap() != nullptr) {
3143 continue;
3144 }
3145
3146 if (fLights->light(i).isRadial()) {
3147 shMapSize.fHeight = 1;
3148 shMapSize.fWidth = (int) picture->cullRect().width();
3149
3150 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3151 kBGRA_8888_SkColorType,
3152 kOpaque_SkAlphaType);
3153
3154 // Create new surface (that matches the backend of canvas)
3155 // for each shadow map
3156 sk_sp<SkSurface> surf(this->makeSurface(info));
3157
3158 // Wrap another SPFCanvas around the surface
3159 SkCanvas* depthMapCanvas = surf->getCanvas();
3160
3161 SkLights::Builder builder;
3162 builder.add(fLights->light(i));
3163 sk_sp<SkLights> curLight = builder.finish();
3164
3165 sk_sp<SkShader> shadowMapShader;
3166 shadowMapShader = SkRadialShadowMapShader::Make(
3167 povDepthShader, curLight,
3168 (int) picture->cullRect().width(),
3169 (int) picture->cullRect().height());
3170
3171 SkPaint shadowMapPaint;
3172 shadowMapPaint.setShader(std::move(shadowMapShader));
3173
3174 depthMapCanvas->setLights(curLight);
3175
3176 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3177 diffuseMap->height()),
3178 shadowMapPaint);
3179
3180 depthMap = surf->makeImageSnapshot();
3181
3182 } else {
3183 // TODO: compute the correct size of the depth map from the light properties
3184 // TODO: maybe add a kDepth_8_SkColorType
3185 // TODO: find actual max depth of picture
3186 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3187 fLights->light(i), 255,
3188 (int) picture->cullRect().width(),
3189 (int) picture->cullRect().height());
3190
3191 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3192 kBGRA_8888_SkColorType,
3193 kOpaque_SkAlphaType);
3194
3195 // Create a new surface (that matches the backend of canvas)
3196 // for each shadow map
3197 sk_sp<SkSurface> surf(this->makeSurface(info));
3198
3199 // Wrap another SPFCanvas around the surface
3200 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3201 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3202 depthMapCanvas->setShadowParams(params);
3203
3204 // set the depth map canvas to have the light we're drawing.
3205 SkLights::Builder builder;
3206 builder.add(fLights->light(i));
3207 sk_sp<SkLights> curLight = builder.finish();
3208 depthMapCanvas->setLights(std::move(curLight));
3209
3210 depthMapCanvas->drawPicture(picture);
3211 depthMap = surf->makeImageSnapshot();
3212 }
3213
3214 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3215 fLights->light(i).setShadowMap(std::move(depthMap));
3216 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3217 // we blur the variance map
3218 SkPaint blurPaint;
3219 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3220 params.fShadowRadius, nullptr));
3221
3222 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3223 kBGRA_8888_SkColorType,
3224 kOpaque_SkAlphaType);
3225
3226 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3227
3228 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3229
3230 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3231 }
3232 }
3233
3234 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003235 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3236 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003237 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003238 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003239 diffuseMap->height(),
3240 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003241
3242 shadowPaint.setShader(shadowShader);
3243
3244 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003245}
3246#endif
3247
reed@android.com8a1c16f2008-12-17 15:59:43 +00003248///////////////////////////////////////////////////////////////////////////////
3249///////////////////////////////////////////////////////////////////////////////
3250
reed3aafe112016-08-18 12:45:34 -07003251SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003252 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003253
3254 SkASSERT(canvas);
3255
reed3aafe112016-08-18 12:45:34 -07003256 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003257 fDone = !fImpl->next();
3258}
3259
3260SkCanvas::LayerIter::~LayerIter() {
3261 fImpl->~SkDrawIter();
3262}
3263
3264void SkCanvas::LayerIter::next() {
3265 fDone = !fImpl->next();
3266}
3267
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003268SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003269 return fImpl->getDevice();
3270}
3271
3272const SkMatrix& SkCanvas::LayerIter::matrix() const {
3273 return fImpl->getMatrix();
3274}
3275
3276const SkPaint& SkCanvas::LayerIter::paint() const {
3277 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003278 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003279 paint = &fDefaultPaint;
3280 }
3281 return *paint;
3282}
3283
reed1e7f5e72016-04-27 07:49:17 -07003284const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003285int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3286int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003287
3288///////////////////////////////////////////////////////////////////////////////
3289
fmalitac3b589a2014-06-05 12:40:07 -07003290SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003291
3292///////////////////////////////////////////////////////////////////////////////
3293
3294static bool supported_for_raster_canvas(const SkImageInfo& info) {
3295 switch (info.alphaType()) {
3296 case kPremul_SkAlphaType:
3297 case kOpaque_SkAlphaType:
3298 break;
3299 default:
3300 return false;
3301 }
3302
3303 switch (info.colorType()) {
3304 case kAlpha_8_SkColorType:
3305 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003306 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003307 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003308 break;
3309 default:
3310 return false;
3311 }
3312
3313 return true;
3314}
3315
Mike Reed5df49342016-11-12 08:06:55 -06003316std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3317 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003318 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003319 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003320 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003321
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003322 SkBitmap bitmap;
3323 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003324 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003325 }
Mike Reed5df49342016-11-12 08:06:55 -06003326 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003327}
reedd5fa1a42014-08-09 11:08:05 -07003328
3329///////////////////////////////////////////////////////////////////////////////
3330
3331SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003332 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003333 : fCanvas(canvas)
3334 , fSaveCount(canvas->getSaveCount())
3335{
bsalomon49f085d2014-09-05 13:34:00 -07003336 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003337 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003338 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003339 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003340 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003341 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003342 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003343 canvas->save();
3344 }
mtklein6cfa73a2014-08-13 13:33:49 -07003345
bsalomon49f085d2014-09-05 13:34:00 -07003346 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003347 canvas->concat(*matrix);
3348 }
3349}
3350
3351SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3352 fCanvas->restoreToCount(fSaveCount);
3353}
reede8f30622016-03-23 18:59:25 -07003354
Florin Malitaee424ac2016-12-01 12:47:59 -05003355///////////////////////////////////////////////////////////////////////////////
3356
3357SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3358 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3359
Florin Malita439ace92016-12-02 12:05:41 -05003360SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3361 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3362
Florin Malitaee424ac2016-12-01 12:47:59 -05003363SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3364 (void)this->INHERITED::getSaveLayerStrategy(rec);
3365 return kNoLayer_SaveLayerStrategy;
3366}
3367
3368///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003369
reed73603f32016-09-20 08:42:38 -07003370static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3371static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3372static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3373static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3374static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3375static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003376
3377///////////////////////////////////////////////////////////////////////////////////////////////////
3378
3379SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3380 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3381 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3382 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3383 SkIPoint origin = dev->getOrigin();
3384 SkMatrix ctm = this->getTotalMatrix();
3385 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3386
3387 SkIRect clip = fMCRec->fRasterClip.getBounds();
3388 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003389 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003390 clip.setEmpty();
3391 }
3392
3393 fAllocator->updateHandle(handle, ctm, clip);
3394 return handle;
3395 }
3396 return nullptr;
3397}
3398
3399static bool install(SkBitmap* bm, const SkImageInfo& info,
3400 const SkRasterHandleAllocator::Rec& rec) {
3401 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3402 rec.fReleaseProc, rec.fReleaseCtx);
3403}
3404
3405SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3406 SkBitmap* bm) {
3407 SkRasterHandleAllocator::Rec rec;
3408 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3409 return nullptr;
3410 }
3411 return rec.fHandle;
3412}
3413
3414std::unique_ptr<SkCanvas>
3415SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3416 const SkImageInfo& info, const Rec* rec) {
3417 if (!alloc || !supported_for_raster_canvas(info)) {
3418 return nullptr;
3419 }
3420
3421 SkBitmap bm;
3422 Handle hndl;
3423
3424 if (rec) {
3425 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3426 } else {
3427 hndl = alloc->allocBitmap(info, &bm);
3428 }
3429 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3430}