blob: 7596c3a70247d5f34c56b4a66290c5159fbba472 [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
reed@google.com3b3e8952012-08-16 20:53:31 +00001745bool SkCanvas::getClipBounds(SkRect* bounds) const {
Mike Reed918e1442017-01-23 11:39:45 -05001746 SkIRect ibounds = this->getDeviceClipBounds();
1747 if (ibounds.isEmpty()) {
1748 if (bounds) {
1749 bounds->setEmpty();
1750 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001751 return false;
1752 }
1753
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001754 SkMatrix inverse;
1755 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001756 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001757 if (bounds) {
1758 bounds->setEmpty();
1759 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001760 return false;
1761 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001762
bsalomon49f085d2014-09-05 13:34:00 -07001763 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001764 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001765 // adjust it outwards in case we are antialiasing
1766 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001767
reed@google.com8f4d2302013-12-17 16:44:46 +00001768 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1769 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001770 inverse.mapRect(bounds, r);
1771 }
1772 return true;
1773}
1774
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001775bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001776 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001777 if (clip.isEmpty()) {
1778 if (bounds) {
1779 bounds->setEmpty();
1780 }
1781 return false;
1782 }
1783
bsalomon49f085d2014-09-05 13:34:00 -07001784 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001785 *bounds = clip.getBounds();
1786 }
1787 return true;
1788}
1789
reed@android.com8a1c16f2008-12-17 15:59:43 +00001790const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001791 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001792}
1793
Mike Reed3726a4a2017-01-19 11:36:41 -05001794void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1795 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1796 if (this->getGrContext()) {
1797 SkPath path;
1798 this->getClipStack()->asPath(&path);
1799 SkISize size = this->getBaseLayerSize();
1800 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1801 } else {
1802 *rgn = fMCRec->fRasterClip.forceGetBW();
1803 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001804}
1805
Brian Osman11052242016-10-27 14:47:55 -04001806GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001807 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001808 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001809}
1810
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001811GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001812 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001813 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001814}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001815
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001816void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1817 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001818 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001819 if (outer.isEmpty()) {
1820 return;
1821 }
1822 if (inner.isEmpty()) {
1823 this->drawRRect(outer, paint);
1824 return;
1825 }
1826
1827 // We don't have this method (yet), but technically this is what we should
1828 // be able to assert...
1829 // SkASSERT(outer.contains(inner));
1830 //
1831 // For now at least check for containment of bounds
1832 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1833
1834 this->onDrawDRRect(outer, inner, paint);
1835}
1836
reed41af9662015-01-05 07:49:08 -08001837// These need to stop being virtual -- clients need to override the onDraw... versions
1838
1839void SkCanvas::drawPaint(const SkPaint& paint) {
1840 this->onDrawPaint(paint);
1841}
1842
1843void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1844 this->onDrawRect(r, paint);
1845}
1846
msarettdca352e2016-08-26 06:37:45 -07001847void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1848 if (region.isEmpty()) {
1849 return;
1850 }
1851
1852 if (region.isRect()) {
1853 return this->drawIRect(region.getBounds(), paint);
1854 }
1855
1856 this->onDrawRegion(region, paint);
1857}
1858
reed41af9662015-01-05 07:49:08 -08001859void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1860 this->onDrawOval(r, paint);
1861}
1862
1863void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1864 this->onDrawRRect(rrect, paint);
1865}
1866
1867void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1868 this->onDrawPoints(mode, count, pts, paint);
1869}
1870
1871void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001872 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001873 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reedfaba3712016-11-03 14:45:31 -04001874 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, bmode,
reed41af9662015-01-05 07:49:08 -08001875 indices, indexCount, paint);
1876}
1877
1878void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1879 this->onDrawPath(path, paint);
1880}
1881
reeda85d4d02015-05-06 12:56:48 -07001882void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001883 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001884 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001885}
1886
reede47829b2015-08-06 10:02:53 -07001887void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1888 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001889 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001890 if (dst.isEmpty() || src.isEmpty()) {
1891 return;
1892 }
1893 this->onDrawImageRect(image, &src, dst, paint, constraint);
1894}
reed41af9662015-01-05 07:49:08 -08001895
reed84984ef2015-07-17 07:09:43 -07001896void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1897 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001898 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001899 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001900}
1901
reede47829b2015-08-06 10:02:53 -07001902void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1903 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001904 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001905 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1906 constraint);
1907}
reede47829b2015-08-06 10:02:53 -07001908
reed4c21dc52015-06-25 12:32:03 -07001909void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1910 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001911 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001912 if (dst.isEmpty()) {
1913 return;
1914 }
msarett552bca92016-08-03 06:53:26 -07001915 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1916 this->onDrawImageNine(image, center, dst, paint);
1917 } else {
reede47829b2015-08-06 10:02:53 -07001918 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001919 }
reed4c21dc52015-06-25 12:32:03 -07001920}
1921
msarett16882062016-08-16 09:31:08 -07001922void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1923 const SkPaint* paint) {
1924 RETURN_ON_NULL(image);
1925 if (dst.isEmpty()) {
1926 return;
1927 }
msarett71df2d72016-09-30 12:41:42 -07001928
1929 SkIRect bounds;
1930 Lattice latticePlusBounds = lattice;
1931 if (!latticePlusBounds.fBounds) {
1932 bounds = SkIRect::MakeWH(image->width(), image->height());
1933 latticePlusBounds.fBounds = &bounds;
1934 }
1935
1936 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1937 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001938 } else {
1939 this->drawImageRect(image, dst, paint);
1940 }
1941}
1942
reed41af9662015-01-05 07:49:08 -08001943void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001944 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001945 return;
1946 }
reed41af9662015-01-05 07:49:08 -08001947 this->onDrawBitmap(bitmap, dx, dy, paint);
1948}
1949
reede47829b2015-08-06 10:02:53 -07001950void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001951 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001952 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001953 return;
1954 }
reede47829b2015-08-06 10:02:53 -07001955 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001956}
1957
reed84984ef2015-07-17 07:09:43 -07001958void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1959 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001960 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001961}
1962
reede47829b2015-08-06 10:02:53 -07001963void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1964 SrcRectConstraint constraint) {
1965 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1966 constraint);
1967}
reede47829b2015-08-06 10:02:53 -07001968
reed41af9662015-01-05 07:49:08 -08001969void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1970 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001971 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001972 return;
1973 }
msarett552bca92016-08-03 06:53:26 -07001974 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1975 this->onDrawBitmapNine(bitmap, center, dst, paint);
1976 } else {
reeda5517e22015-07-14 10:54:12 -07001977 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001978 }
reed41af9662015-01-05 07:49:08 -08001979}
1980
msarettc573a402016-08-02 08:05:56 -07001981void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1982 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001983 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001984 return;
1985 }
msarett71df2d72016-09-30 12:41:42 -07001986
1987 SkIRect bounds;
1988 Lattice latticePlusBounds = lattice;
1989 if (!latticePlusBounds.fBounds) {
1990 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1991 latticePlusBounds.fBounds = &bounds;
1992 }
1993
1994 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1995 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001996 } else {
msarett16882062016-08-16 09:31:08 -07001997 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001998 }
msarettc573a402016-08-02 08:05:56 -07001999}
2000
reed71c3c762015-06-24 10:29:17 -07002001void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002002 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002003 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002004 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002005 if (count <= 0) {
2006 return;
2007 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002008 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002009 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002010 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002011}
2012
reedf70b5312016-03-04 16:36:20 -08002013void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2014 if (key) {
2015 this->onDrawAnnotation(rect, key, value);
2016 }
2017}
2018
reede47829b2015-08-06 10:02:53 -07002019void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2020 const SkPaint* paint, SrcRectConstraint constraint) {
2021 if (src) {
2022 this->drawImageRect(image, *src, dst, paint, constraint);
2023 } else {
2024 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2025 dst, paint, constraint);
2026 }
2027}
2028void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2029 const SkPaint* paint, SrcRectConstraint constraint) {
2030 if (src) {
2031 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2032 } else {
2033 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2034 dst, paint, constraint);
2035 }
2036}
2037
tomhudsoncb3bd182016-05-18 07:24:16 -07002038void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2039 SkIRect layer_bounds = this->getTopLayerBounds();
2040 if (matrix) {
2041 *matrix = this->getTotalMatrix();
2042 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2043 }
2044 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002045 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002046 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2047 }
2048}
2049
reed@android.com8a1c16f2008-12-17 15:59:43 +00002050//////////////////////////////////////////////////////////////////////////////
2051// These are the virtual drawing methods
2052//////////////////////////////////////////////////////////////////////////////
2053
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002054void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002055 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002056 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2057 }
2058}
2059
reed41af9662015-01-05 07:49:08 -08002060void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002061 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002062 this->internalDrawPaint(paint);
2063}
2064
2065void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002066 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002067
2068 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002069 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002070 }
2071
reed@google.com4e2b3d32011-04-07 14:18:59 +00002072 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002073}
2074
reed41af9662015-01-05 07:49:08 -08002075void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2076 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002077 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002078 if ((long)count <= 0) {
2079 return;
2080 }
2081
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002082 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002083 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002084 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002085 // special-case 2 points (common for drawing a single line)
2086 if (2 == count) {
2087 r.set(pts[0], pts[1]);
2088 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002089 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002090 }
senorblanco87e066e2015-10-28 11:23:36 -07002091 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2092 return;
2093 }
2094 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002095 }
reed@google.coma584aed2012-05-16 14:06:02 +00002096
halcanary96fcdcc2015-08-27 07:41:13 -07002097 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002098
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002099 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002100
reed@android.com8a1c16f2008-12-17 15:59:43 +00002101 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002102 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002103 }
reed@google.com4b226022011-01-11 18:32:13 +00002104
reed@google.com4e2b3d32011-04-07 14:18:59 +00002105 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002106}
2107
reed4a167172016-08-18 17:15:25 -07002108static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2109 return ((intptr_t)paint.getImageFilter() |
2110#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2111 (intptr_t)canvas->getDrawFilter() |
2112#endif
2113 (intptr_t)paint.getLooper() ) != 0;
2114}
2115
reed41af9662015-01-05 07:49:08 -08002116void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002117 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002118 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002119 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002120 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002121 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2122 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2123 SkRect tmp(r);
2124 tmp.sort();
2125
senorblanco87e066e2015-10-28 11:23:36 -07002126 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2127 return;
2128 }
2129 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002130 }
reed@google.com4b226022011-01-11 18:32:13 +00002131
reed4a167172016-08-18 17:15:25 -07002132 if (needs_autodrawlooper(this, paint)) {
2133 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002134
reed4a167172016-08-18 17:15:25 -07002135 while (iter.next()) {
2136 iter.fDevice->drawRect(iter, r, looper.paint());
2137 }
2138
2139 LOOPER_END
2140 } else {
2141 this->predrawNotify(bounds, &paint, false);
2142 SkDrawIter iter(this);
2143 while (iter.next()) {
2144 iter.fDevice->drawRect(iter, r, paint);
2145 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002146 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002147}
2148
msarett44df6512016-08-25 13:54:30 -07002149void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2150 SkRect storage;
2151 SkRect regionRect = SkRect::Make(region.getBounds());
2152 const SkRect* bounds = nullptr;
2153 if (paint.canComputeFastBounds()) {
2154 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2155 return;
2156 }
2157 bounds = &regionRect;
2158 }
2159
2160 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2161
2162 while (iter.next()) {
2163 iter.fDevice->drawRegion(iter, region, looper.paint());
2164 }
2165
2166 LOOPER_END
2167}
2168
reed41af9662015-01-05 07:49:08 -08002169void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002170 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002171 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002172 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002173 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002174 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2175 return;
2176 }
2177 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002178 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002179
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002180 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002181
2182 while (iter.next()) {
2183 iter.fDevice->drawOval(iter, oval, looper.paint());
2184 }
2185
2186 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002187}
2188
bsalomonac3aa242016-08-19 11:25:19 -07002189void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2190 SkScalar sweepAngle, bool useCenter,
2191 const SkPaint& paint) {
2192 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2193 const SkRect* bounds = nullptr;
2194 if (paint.canComputeFastBounds()) {
2195 SkRect storage;
2196 // Note we're using the entire oval as the bounds.
2197 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2198 return;
2199 }
2200 bounds = &oval;
2201 }
2202
2203 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2204
2205 while (iter.next()) {
2206 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2207 }
2208
2209 LOOPER_END
2210}
2211
reed41af9662015-01-05 07:49:08 -08002212void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002213 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002214 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002215 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002216 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002217 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2218 return;
2219 }
2220 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002221 }
2222
2223 if (rrect.isRect()) {
2224 // call the non-virtual version
2225 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002226 return;
2227 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002228 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002229 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2230 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002231 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002232
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002233 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002234
2235 while (iter.next()) {
2236 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2237 }
2238
2239 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002240}
2241
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002242void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2243 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002244 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002245 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002246 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002247 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2248 return;
2249 }
2250 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002251 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002252
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002253 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002254
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002255 while (iter.next()) {
2256 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2257 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002258
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002259 LOOPER_END
2260}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002261
reed41af9662015-01-05 07:49:08 -08002262void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002263 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002264 if (!path.isFinite()) {
2265 return;
2266 }
2267
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002268 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002269 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002270 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002271 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002272 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2273 return;
2274 }
2275 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002276 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002277
2278 const SkRect& r = path.getBounds();
2279 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002280 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002281 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002282 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002283 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002284 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002285
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002286 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002287
2288 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002289 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290 }
2291
reed@google.com4e2b3d32011-04-07 14:18:59 +00002292 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002293}
2294
reed262a71b2015-12-05 13:07:27 -08002295bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002296 if (!paint.getImageFilter()) {
2297 return false;
2298 }
2299
2300 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002301 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002302 return false;
2303 }
2304
2305 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2306 // Once we can filter and the filter will return a result larger than itself, we should be
2307 // able to remove this constraint.
2308 // skbug.com/4526
2309 //
2310 SkPoint pt;
2311 ctm.mapXY(x, y, &pt);
2312 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2313 return ir.contains(fMCRec->fRasterClip.getBounds());
2314}
2315
reeda85d4d02015-05-06 12:56:48 -07002316void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002317 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002318 SkRect bounds = SkRect::MakeXYWH(x, y,
2319 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002320 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002321 SkRect tmp = bounds;
2322 if (paint) {
2323 paint->computeFastBounds(tmp, &tmp);
2324 }
2325 if (this->quickReject(tmp)) {
2326 return;
2327 }
reeda85d4d02015-05-06 12:56:48 -07002328 }
halcanary9d524f22016-03-29 09:03:52 -07002329
reeda85d4d02015-05-06 12:56:48 -07002330 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002331 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002332 paint = lazy.init();
2333 }
reed262a71b2015-12-05 13:07:27 -08002334
reeda2217ef2016-07-20 06:04:34 -07002335 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002336 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2337 *paint);
2338 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002339 special = this->getDevice()->makeSpecial(image);
2340 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002341 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002342 }
2343 }
2344
reed262a71b2015-12-05 13:07:27 -08002345 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2346
reeda85d4d02015-05-06 12:56:48 -07002347 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002348 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002349 if (special) {
2350 SkPoint pt;
2351 iter.fMatrix->mapXY(x, y, &pt);
2352 iter.fDevice->drawSpecial(iter, special.get(),
2353 SkScalarRoundToInt(pt.fX),
2354 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002355 } else {
2356 iter.fDevice->drawImage(iter, image, x, y, pnt);
2357 }
reeda85d4d02015-05-06 12:56:48 -07002358 }
halcanary9d524f22016-03-29 09:03:52 -07002359
reeda85d4d02015-05-06 12:56:48 -07002360 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002361}
2362
reed41af9662015-01-05 07:49:08 -08002363void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002364 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002365 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002366 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002367 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002368 if (paint) {
2369 paint->computeFastBounds(dst, &storage);
2370 }
2371 if (this->quickReject(storage)) {
2372 return;
2373 }
reeda85d4d02015-05-06 12:56:48 -07002374 }
2375 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002376 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002377 paint = lazy.init();
2378 }
halcanary9d524f22016-03-29 09:03:52 -07002379
senorblancoc41e7e12015-12-07 12:51:30 -08002380 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002381 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002382
reeda85d4d02015-05-06 12:56:48 -07002383 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002384 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002385 }
halcanary9d524f22016-03-29 09:03:52 -07002386
reeda85d4d02015-05-06 12:56:48 -07002387 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002388}
2389
reed41af9662015-01-05 07:49:08 -08002390void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002391 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002392 SkDEBUGCODE(bitmap.validate();)
2393
reed33366972015-10-08 09:22:02 -07002394 if (bitmap.drawsNothing()) {
2395 return;
2396 }
2397
2398 SkLazyPaint lazy;
2399 if (nullptr == paint) {
2400 paint = lazy.init();
2401 }
2402
2403 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2404
2405 SkRect storage;
2406 const SkRect* bounds = nullptr;
2407 if (paint->canComputeFastBounds()) {
2408 bitmap.getBounds(&storage);
2409 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002410 SkRect tmp = storage;
2411 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2412 return;
2413 }
2414 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002415 }
reed@google.com4b226022011-01-11 18:32:13 +00002416
reeda2217ef2016-07-20 06:04:34 -07002417 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002418 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2419 *paint);
2420 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002421 special = this->getDevice()->makeSpecial(bitmap);
2422 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002423 drawAsSprite = false;
2424 }
2425 }
2426
reed262a71b2015-12-05 13:07:27 -08002427 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002428
2429 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002430 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002431 if (special) {
reed262a71b2015-12-05 13:07:27 -08002432 SkPoint pt;
2433 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002434 iter.fDevice->drawSpecial(iter, special.get(),
2435 SkScalarRoundToInt(pt.fX),
2436 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002437 } else {
2438 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2439 }
reed33366972015-10-08 09:22:02 -07002440 }
msarettfbfa2582016-08-12 08:29:08 -07002441
reed33366972015-10-08 09:22:02 -07002442 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002443}
2444
reed@google.com9987ec32011-09-07 11:57:52 +00002445// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002446void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002447 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002448 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002449 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002450 return;
2451 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002452
halcanary96fcdcc2015-08-27 07:41:13 -07002453 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002454 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002455 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2456 return;
2457 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002458 }
reed@google.com3d608122011-11-21 15:16:16 +00002459
reed@google.com33535f32012-09-25 15:37:50 +00002460 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002461 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002462 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002463 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002464
senorblancoc41e7e12015-12-07 12:51:30 -08002465 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002466 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002467
reed@google.com33535f32012-09-25 15:37:50 +00002468 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002469 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002470 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002471
reed@google.com33535f32012-09-25 15:37:50 +00002472 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473}
2474
reed41af9662015-01-05 07:49:08 -08002475void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002476 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002477 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002478 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002479 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002480}
2481
reed4c21dc52015-06-25 12:32:03 -07002482void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2483 const SkPaint* paint) {
2484 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002485
halcanary96fcdcc2015-08-27 07:41:13 -07002486 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002487 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002488 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2489 return;
2490 }
reed@google.com3d608122011-11-21 15:16:16 +00002491 }
halcanary9d524f22016-03-29 09:03:52 -07002492
reed4c21dc52015-06-25 12:32:03 -07002493 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002494 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002495 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002496 }
halcanary9d524f22016-03-29 09:03:52 -07002497
senorblancoc41e7e12015-12-07 12:51:30 -08002498 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002499
reed4c21dc52015-06-25 12:32:03 -07002500 while (iter.next()) {
2501 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002502 }
halcanary9d524f22016-03-29 09:03:52 -07002503
reed4c21dc52015-06-25 12:32:03 -07002504 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002505}
2506
reed41af9662015-01-05 07:49:08 -08002507void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2508 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002509 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002510 SkDEBUGCODE(bitmap.validate();)
2511
halcanary96fcdcc2015-08-27 07:41:13 -07002512 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002513 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002514 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2515 return;
2516 }
reed4c21dc52015-06-25 12:32:03 -07002517 }
halcanary9d524f22016-03-29 09:03:52 -07002518
reed4c21dc52015-06-25 12:32:03 -07002519 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002520 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002521 paint = lazy.init();
2522 }
halcanary9d524f22016-03-29 09:03:52 -07002523
senorblancoc41e7e12015-12-07 12:51:30 -08002524 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002525
reed4c21dc52015-06-25 12:32:03 -07002526 while (iter.next()) {
2527 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2528 }
halcanary9d524f22016-03-29 09:03:52 -07002529
reed4c21dc52015-06-25 12:32:03 -07002530 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002531}
2532
msarett16882062016-08-16 09:31:08 -07002533void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2534 const SkPaint* paint) {
2535 if (nullptr == paint || paint->canComputeFastBounds()) {
2536 SkRect storage;
2537 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2538 return;
2539 }
2540 }
2541
2542 SkLazyPaint lazy;
2543 if (nullptr == paint) {
2544 paint = lazy.init();
2545 }
2546
2547 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2548
2549 while (iter.next()) {
2550 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2551 }
2552
2553 LOOPER_END
2554}
2555
2556void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2557 const SkRect& dst, const SkPaint* paint) {
2558 if (nullptr == paint || paint->canComputeFastBounds()) {
2559 SkRect storage;
2560 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2561 return;
2562 }
2563 }
2564
2565 SkLazyPaint lazy;
2566 if (nullptr == paint) {
2567 paint = lazy.init();
2568 }
2569
2570 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2571
2572 while (iter.next()) {
2573 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2574 }
2575
2576 LOOPER_END
2577}
2578
reed@google.comf67e4cf2011-03-15 20:56:58 +00002579class SkDeviceFilteredPaint {
2580public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002581 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002582 uint32_t filteredFlags = device->filterTextFlags(paint);
2583 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002584 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002585 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002586 fPaint = newPaint;
2587 } else {
2588 fPaint = &paint;
2589 }
2590 }
2591
reed@google.comf67e4cf2011-03-15 20:56:58 +00002592 const SkPaint& paint() const { return *fPaint; }
2593
2594private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002595 const SkPaint* fPaint;
2596 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002597};
2598
bungeman@google.com52c748b2011-08-22 21:30:43 +00002599void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2600 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002601 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002602 draw.fDevice->drawRect(draw, r, paint);
2603 } else {
2604 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002605 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002606 draw.fDevice->drawRect(draw, r, p);
2607 }
2608}
2609
2610void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2611 const char text[], size_t byteLength,
2612 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002613 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002614
2615 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002616 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002617 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002618 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002619 return;
2620 }
2621
2622 SkScalar width = 0;
2623 SkPoint start;
2624
2625 start.set(0, 0); // to avoid warning
2626 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2627 SkPaint::kStrikeThruText_Flag)) {
2628 width = paint.measureText(text, byteLength);
2629
2630 SkScalar offsetX = 0;
2631 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2632 offsetX = SkScalarHalf(width);
2633 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2634 offsetX = width;
2635 }
2636 start.set(x - offsetX, y);
2637 }
2638
2639 if (0 == width) {
2640 return;
2641 }
2642
2643 uint32_t flags = paint.getFlags();
2644
2645 if (flags & (SkPaint::kUnderlineText_Flag |
2646 SkPaint::kStrikeThruText_Flag)) {
2647 SkScalar textSize = paint.getTextSize();
2648 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2649 SkRect r;
2650
2651 r.fLeft = start.fX;
2652 r.fRight = start.fX + width;
2653
2654 if (flags & SkPaint::kUnderlineText_Flag) {
2655 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2656 start.fY);
2657 r.fTop = offset;
2658 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002659 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002660 }
2661 if (flags & SkPaint::kStrikeThruText_Flag) {
2662 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2663 start.fY);
2664 r.fTop = offset;
2665 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002666 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002667 }
2668 }
2669}
2670
reed@google.come0d9ce82014-04-23 04:00:17 +00002671void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2672 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002673 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002674
2675 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002676 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002677 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002678 DrawTextDecorations(iter, dfp.paint(),
2679 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002680 }
2681
reed@google.com4e2b3d32011-04-07 14:18:59 +00002682 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002683}
2684
reed@google.come0d9ce82014-04-23 04:00:17 +00002685void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2686 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002687 SkPoint textOffset = SkPoint::Make(0, 0);
2688
halcanary96fcdcc2015-08-27 07:41:13 -07002689 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002690
reed@android.com8a1c16f2008-12-17 15:59:43 +00002691 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002692 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002693 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002694 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002695 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002696
reed@google.com4e2b3d32011-04-07 14:18:59 +00002697 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698}
2699
reed@google.come0d9ce82014-04-23 04:00:17 +00002700void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2701 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002702
2703 SkPoint textOffset = SkPoint::Make(0, constY);
2704
halcanary96fcdcc2015-08-27 07:41:13 -07002705 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002706
reed@android.com8a1c16f2008-12-17 15:59:43 +00002707 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002708 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002709 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002710 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002712
reed@google.com4e2b3d32011-04-07 14:18:59 +00002713 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714}
2715
reed@google.come0d9ce82014-04-23 04:00:17 +00002716void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2717 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002718 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002719
reed@android.com8a1c16f2008-12-17 15:59:43 +00002720 while (iter.next()) {
2721 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002722 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002724
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002725 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002726}
2727
reed45561a02016-07-07 12:47:17 -07002728void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2729 const SkRect* cullRect, const SkPaint& paint) {
2730 if (cullRect && this->quickReject(*cullRect)) {
2731 return;
2732 }
2733
2734 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2735
2736 while (iter.next()) {
2737 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2738 }
2739
2740 LOOPER_END
2741}
2742
fmalita00d5c2c2014-08-21 08:53:26 -07002743void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2744 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002745
fmalita85d5eb92015-03-04 11:20:12 -08002746 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002747 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002748 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002749 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002750 SkRect tmp;
2751 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2752 return;
2753 }
2754 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002755 }
2756
fmalita024f9962015-03-03 19:08:17 -08002757 // We cannot filter in the looper as we normally do, because the paint is
2758 // incomplete at this point (text-related attributes are embedded within blob run paints).
2759 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002760 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002761
fmalita85d5eb92015-03-04 11:20:12 -08002762 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002763
fmalitaaa1b9122014-08-28 14:32:24 -07002764 while (iter.next()) {
2765 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002766 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002767 }
2768
fmalitaaa1b9122014-08-28 14:32:24 -07002769 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002770
2771 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002772}
2773
reed@google.come0d9ce82014-04-23 04:00:17 +00002774// These will become non-virtual, so they always call the (virtual) onDraw... method
2775void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2776 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002777 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002778 if (byteLength) {
2779 this->onDrawText(text, byteLength, x, y, paint);
2780 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002781}
2782void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2783 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002784 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002785 if (byteLength) {
2786 this->onDrawPosText(text, byteLength, pos, paint);
2787 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002788}
2789void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2790 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002791 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002792 if (byteLength) {
2793 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2794 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002795}
2796void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2797 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002798 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002799 if (byteLength) {
2800 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2801 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002802}
reed45561a02016-07-07 12:47:17 -07002803void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2804 const SkRect* cullRect, const SkPaint& paint) {
2805 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2806 if (byteLength) {
2807 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2808 }
2809}
fmalita00d5c2c2014-08-21 08:53:26 -07002810void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2811 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002812 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002813 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002814 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002815}
reed@google.come0d9ce82014-04-23 04:00:17 +00002816
reed41af9662015-01-05 07:49:08 -08002817void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2818 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002819 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002820 const uint16_t indices[], int indexCount,
2821 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002822 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002823 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002824
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825 while (iter.next()) {
2826 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002827 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002828 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002829 }
reed@google.com4b226022011-01-11 18:32:13 +00002830
reed@google.com4e2b3d32011-04-07 14:18:59 +00002831 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002832}
2833
dandovb3c9d1c2014-08-12 08:34:29 -07002834void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002835 const SkPoint texCoords[4], SkBlendMode bmode,
2836 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002837 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002838 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002839 return;
2840 }
mtklein6cfa73a2014-08-13 13:33:49 -07002841
Mike Reedfaba3712016-11-03 14:45:31 -04002842 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002843}
2844
2845void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002846 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002847 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002848 // Since a patch is always within the convex hull of the control points, we discard it when its
2849 // bounding rectangle is completely outside the current clip.
2850 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002851 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002852 if (this->quickReject(bounds)) {
2853 return;
2854 }
mtklein6cfa73a2014-08-13 13:33:49 -07002855
halcanary96fcdcc2015-08-27 07:41:13 -07002856 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002857
dandovecfff212014-08-04 10:02:00 -07002858 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002859 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002860 }
mtklein6cfa73a2014-08-13 13:33:49 -07002861
dandovecfff212014-08-04 10:02:00 -07002862 LOOPER_END
2863}
2864
reeda8db7282015-07-07 10:22:31 -07002865void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002866 RETURN_ON_NULL(dr);
2867 if (x || y) {
2868 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2869 this->onDrawDrawable(dr, &matrix);
2870 } else {
2871 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002872 }
2873}
2874
reeda8db7282015-07-07 10:22:31 -07002875void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002876 RETURN_ON_NULL(dr);
2877 if (matrix && matrix->isIdentity()) {
2878 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002879 }
reede3b38ce2016-01-08 09:18:44 -08002880 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002881}
2882
2883void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002884 // drawable bounds are no longer reliable (e.g. android displaylist)
2885 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002886 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002887}
2888
reed71c3c762015-06-24 10:29:17 -07002889void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002890 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002891 const SkRect* cull, const SkPaint* paint) {
2892 if (cull && this->quickReject(*cull)) {
2893 return;
2894 }
2895
2896 SkPaint pnt;
2897 if (paint) {
2898 pnt = *paint;
2899 }
halcanary9d524f22016-03-29 09:03:52 -07002900
halcanary96fcdcc2015-08-27 07:41:13 -07002901 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002902 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002903 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002904 }
2905 LOOPER_END
2906}
2907
reedf70b5312016-03-04 16:36:20 -08002908void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2909 SkASSERT(key);
2910
2911 SkPaint paint;
2912 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2913 while (iter.next()) {
2914 iter.fDevice->drawAnnotation(iter, rect, key, value);
2915 }
2916 LOOPER_END
2917}
2918
reed@android.com8a1c16f2008-12-17 15:59:43 +00002919//////////////////////////////////////////////////////////////////////////////
2920// These methods are NOT virtual, and therefore must call back into virtual
2921// methods, rather than actually drawing themselves.
2922//////////////////////////////////////////////////////////////////////////////
2923
reed374772b2016-10-05 17:33:02 -07002924void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002925 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002926 SkPaint paint;
2927
2928 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002929 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002930 this->drawPaint(paint);
2931}
2932
reed374772b2016-10-05 17:33:02 -07002933void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002934 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002935 SkPaint paint;
2936
2937 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002938 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002939 this->drawPaint(paint);
2940}
2941
2942void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002943 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002944 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002945
reed@android.com8a1c16f2008-12-17 15:59:43 +00002946 pt.set(x, y);
2947 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2948}
2949
2950void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002951 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002952 SkPoint pt;
2953 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002954
reed@android.com8a1c16f2008-12-17 15:59:43 +00002955 pt.set(x, y);
2956 paint.setColor(color);
2957 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2958}
2959
2960void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2961 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002962 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002963 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002964
reed@android.com8a1c16f2008-12-17 15:59:43 +00002965 pts[0].set(x0, y0);
2966 pts[1].set(x1, y1);
2967 this->drawPoints(kLines_PointMode, 2, pts, paint);
2968}
2969
2970void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2971 SkScalar right, SkScalar bottom,
2972 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002973 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002974 SkRect r;
2975
2976 r.set(left, top, right, bottom);
2977 this->drawRect(r, paint);
2978}
2979
2980void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2981 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002982 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002983 if (radius < 0) {
2984 radius = 0;
2985 }
2986
2987 SkRect r;
2988 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002989 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002990}
2991
2992void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2993 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002994 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002995 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002996 SkRRect rrect;
2997 rrect.setRectXY(r, rx, ry);
2998 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002999 } else {
3000 this->drawRect(r, paint);
3001 }
3002}
3003
reed@android.com8a1c16f2008-12-17 15:59:43 +00003004void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3005 SkScalar sweepAngle, bool useCenter,
3006 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003007 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003008 if (oval.isEmpty() || !sweepAngle) {
3009 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003010 }
bsalomon21af9ca2016-08-25 12:29:23 -07003011 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003012}
3013
3014void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3015 const SkPath& path, SkScalar hOffset,
3016 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003017 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003018 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003019
reed@android.com8a1c16f2008-12-17 15:59:43 +00003020 matrix.setTranslate(hOffset, vOffset);
3021 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3022}
3023
reed@android.comf76bacf2009-05-13 14:00:33 +00003024///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003025
3026/**
3027 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3028 * against the playback cost of recursing into the subpicture to get at its actual ops.
3029 *
3030 * For now we pick a conservatively small value, though measurement (and other heuristics like
3031 * the type of ops contained) may justify changing this value.
3032 */
3033#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003034
reedd5fa1a42014-08-09 11:08:05 -07003035void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003036 RETURN_ON_NULL(picture);
3037
reed1c2c4412015-04-30 13:09:24 -07003038 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003039 if (matrix && matrix->isIdentity()) {
3040 matrix = nullptr;
3041 }
3042 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3043 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3044 picture->playback(this);
3045 } else {
3046 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003047 }
3048}
robertphillips9b14f262014-06-04 05:40:44 -07003049
reedd5fa1a42014-08-09 11:08:05 -07003050void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3051 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003052 if (!paint || paint->canComputeFastBounds()) {
3053 SkRect bounds = picture->cullRect();
3054 if (paint) {
3055 paint->computeFastBounds(bounds, &bounds);
3056 }
3057 if (matrix) {
3058 matrix->mapRect(&bounds);
3059 }
3060 if (this->quickReject(bounds)) {
3061 return;
3062 }
3063 }
3064
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003065 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003066 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003067}
3068
vjiaoblack95302da2016-07-21 10:25:54 -07003069#ifdef SK_EXPERIMENTAL_SHADOWING
3070void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3071 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003072 const SkPaint* paint,
3073 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003074 RETURN_ON_NULL(picture);
3075
3076 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3077
vjiaoblacke6f5d562016-08-25 06:30:23 -07003078 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003079}
3080
3081void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3082 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003083 const SkPaint* paint,
3084 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003085 if (!paint || paint->canComputeFastBounds()) {
3086 SkRect bounds = picture->cullRect();
3087 if (paint) {
3088 paint->computeFastBounds(bounds, &bounds);
3089 }
3090 if (matrix) {
3091 matrix->mapRect(&bounds);
3092 }
3093 if (this->quickReject(bounds)) {
3094 return;
3095 }
3096 }
3097
3098 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3099
vjiaoblacke6f5d562016-08-25 06:30:23 -07003100 sk_sp<SkImage> povDepthMap;
3101 sk_sp<SkImage> diffuseMap;
3102
vjiaoblack904527d2016-08-09 09:32:09 -07003103 // povDepthMap
3104 {
3105 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003106 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3107 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003108 sk_sp<SkLights> povLight = builder.finish();
3109
3110 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3111 picture->cullRect().height(),
3112 kBGRA_8888_SkColorType,
3113 kOpaque_SkAlphaType);
3114
3115 // Create a new surface (that matches the backend of canvas)
3116 // to create the povDepthMap
3117 sk_sp<SkSurface> surf(this->makeSurface(info));
3118
3119 // Wrap another SPFCanvas around the surface
3120 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3121 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3122
3123 // set the depth map canvas to have the light as the user's POV
3124 depthMapCanvas->setLights(std::move(povLight));
3125
3126 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003127 povDepthMap = surf->makeImageSnapshot();
3128 }
3129
3130 // diffuseMap
3131 {
3132 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3133 picture->cullRect().height(),
3134 kBGRA_8888_SkColorType,
3135 kOpaque_SkAlphaType);
3136
3137 sk_sp<SkSurface> surf(this->makeSurface(info));
3138 surf->getCanvas()->drawPicture(picture);
3139
3140 diffuseMap = surf->makeImageSnapshot();
3141 }
vjiaoblack904527d2016-08-09 09:32:09 -07003142
3143 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3144 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003145 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3146 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003147
3148 // TODO: pass the depth to the shader in vertices, or uniforms
3149 // so we don't have to render depth and color separately
3150 for (int i = 0; i < fLights->numLights(); ++i) {
3151 // skip over ambient lights; they don't cast shadows
3152 // lights that have shadow maps do not need updating (because lights are immutable)
3153 sk_sp<SkImage> depthMap;
3154 SkISize shMapSize;
3155
3156 if (fLights->light(i).getShadowMap() != nullptr) {
3157 continue;
3158 }
3159
3160 if (fLights->light(i).isRadial()) {
3161 shMapSize.fHeight = 1;
3162 shMapSize.fWidth = (int) picture->cullRect().width();
3163
3164 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3165 kBGRA_8888_SkColorType,
3166 kOpaque_SkAlphaType);
3167
3168 // Create new surface (that matches the backend of canvas)
3169 // for each shadow map
3170 sk_sp<SkSurface> surf(this->makeSurface(info));
3171
3172 // Wrap another SPFCanvas around the surface
3173 SkCanvas* depthMapCanvas = surf->getCanvas();
3174
3175 SkLights::Builder builder;
3176 builder.add(fLights->light(i));
3177 sk_sp<SkLights> curLight = builder.finish();
3178
3179 sk_sp<SkShader> shadowMapShader;
3180 shadowMapShader = SkRadialShadowMapShader::Make(
3181 povDepthShader, curLight,
3182 (int) picture->cullRect().width(),
3183 (int) picture->cullRect().height());
3184
3185 SkPaint shadowMapPaint;
3186 shadowMapPaint.setShader(std::move(shadowMapShader));
3187
3188 depthMapCanvas->setLights(curLight);
3189
3190 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3191 diffuseMap->height()),
3192 shadowMapPaint);
3193
3194 depthMap = surf->makeImageSnapshot();
3195
3196 } else {
3197 // TODO: compute the correct size of the depth map from the light properties
3198 // TODO: maybe add a kDepth_8_SkColorType
3199 // TODO: find actual max depth of picture
3200 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3201 fLights->light(i), 255,
3202 (int) picture->cullRect().width(),
3203 (int) picture->cullRect().height());
3204
3205 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3206 kBGRA_8888_SkColorType,
3207 kOpaque_SkAlphaType);
3208
3209 // Create a new surface (that matches the backend of canvas)
3210 // for each shadow map
3211 sk_sp<SkSurface> surf(this->makeSurface(info));
3212
3213 // Wrap another SPFCanvas around the surface
3214 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3215 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3216 depthMapCanvas->setShadowParams(params);
3217
3218 // set the depth map canvas to have the light we're drawing.
3219 SkLights::Builder builder;
3220 builder.add(fLights->light(i));
3221 sk_sp<SkLights> curLight = builder.finish();
3222 depthMapCanvas->setLights(std::move(curLight));
3223
3224 depthMapCanvas->drawPicture(picture);
3225 depthMap = surf->makeImageSnapshot();
3226 }
3227
3228 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3229 fLights->light(i).setShadowMap(std::move(depthMap));
3230 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3231 // we blur the variance map
3232 SkPaint blurPaint;
3233 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3234 params.fShadowRadius, nullptr));
3235
3236 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3237 kBGRA_8888_SkColorType,
3238 kOpaque_SkAlphaType);
3239
3240 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3241
3242 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3243
3244 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3245 }
3246 }
3247
3248 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003249 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3250 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003251 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003252 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003253 diffuseMap->height(),
3254 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003255
3256 shadowPaint.setShader(shadowShader);
3257
3258 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003259}
3260#endif
3261
reed@android.com8a1c16f2008-12-17 15:59:43 +00003262///////////////////////////////////////////////////////////////////////////////
3263///////////////////////////////////////////////////////////////////////////////
3264
reed3aafe112016-08-18 12:45:34 -07003265SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003266 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003267
3268 SkASSERT(canvas);
3269
reed3aafe112016-08-18 12:45:34 -07003270 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003271 fDone = !fImpl->next();
3272}
3273
3274SkCanvas::LayerIter::~LayerIter() {
3275 fImpl->~SkDrawIter();
3276}
3277
3278void SkCanvas::LayerIter::next() {
3279 fDone = !fImpl->next();
3280}
3281
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003282SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003283 return fImpl->getDevice();
3284}
3285
3286const SkMatrix& SkCanvas::LayerIter::matrix() const {
3287 return fImpl->getMatrix();
3288}
3289
3290const SkPaint& SkCanvas::LayerIter::paint() const {
3291 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003292 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003293 paint = &fDefaultPaint;
3294 }
3295 return *paint;
3296}
3297
reed1e7f5e72016-04-27 07:49:17 -07003298const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003299int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3300int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003301
3302///////////////////////////////////////////////////////////////////////////////
3303
fmalitac3b589a2014-06-05 12:40:07 -07003304SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003305
3306///////////////////////////////////////////////////////////////////////////////
3307
3308static bool supported_for_raster_canvas(const SkImageInfo& info) {
3309 switch (info.alphaType()) {
3310 case kPremul_SkAlphaType:
3311 case kOpaque_SkAlphaType:
3312 break;
3313 default:
3314 return false;
3315 }
3316
3317 switch (info.colorType()) {
3318 case kAlpha_8_SkColorType:
3319 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003320 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003321 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003322 break;
3323 default:
3324 return false;
3325 }
3326
3327 return true;
3328}
3329
Mike Reed5df49342016-11-12 08:06:55 -06003330std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3331 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003332 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003333 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003334 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003335
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003336 SkBitmap bitmap;
3337 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003338 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003339 }
Mike Reed5df49342016-11-12 08:06:55 -06003340 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003341}
reedd5fa1a42014-08-09 11:08:05 -07003342
3343///////////////////////////////////////////////////////////////////////////////
3344
3345SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003346 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003347 : fCanvas(canvas)
3348 , fSaveCount(canvas->getSaveCount())
3349{
bsalomon49f085d2014-09-05 13:34:00 -07003350 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003351 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003352 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003353 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003354 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003355 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003356 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003357 canvas->save();
3358 }
mtklein6cfa73a2014-08-13 13:33:49 -07003359
bsalomon49f085d2014-09-05 13:34:00 -07003360 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003361 canvas->concat(*matrix);
3362 }
3363}
3364
3365SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3366 fCanvas->restoreToCount(fSaveCount);
3367}
reede8f30622016-03-23 18:59:25 -07003368
Florin Malitaee424ac2016-12-01 12:47:59 -05003369///////////////////////////////////////////////////////////////////////////////
3370
3371SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3372 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3373
Florin Malita439ace92016-12-02 12:05:41 -05003374SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3375 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3376
Florin Malitaee424ac2016-12-01 12:47:59 -05003377SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3378 (void)this->INHERITED::getSaveLayerStrategy(rec);
3379 return kNoLayer_SaveLayerStrategy;
3380}
3381
3382///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003383
reed73603f32016-09-20 08:42:38 -07003384static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3385static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3386static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3387static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3388static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3389static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003390
3391///////////////////////////////////////////////////////////////////////////////////////////////////
3392
3393SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3394 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3395 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3396 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3397 SkIPoint origin = dev->getOrigin();
3398 SkMatrix ctm = this->getTotalMatrix();
3399 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3400
3401 SkIRect clip = fMCRec->fRasterClip.getBounds();
3402 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003403 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003404 clip.setEmpty();
3405 }
3406
3407 fAllocator->updateHandle(handle, ctm, clip);
3408 return handle;
3409 }
3410 return nullptr;
3411}
3412
3413static bool install(SkBitmap* bm, const SkImageInfo& info,
3414 const SkRasterHandleAllocator::Rec& rec) {
3415 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3416 rec.fReleaseProc, rec.fReleaseCtx);
3417}
3418
3419SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3420 SkBitmap* bm) {
3421 SkRasterHandleAllocator::Rec rec;
3422 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3423 return nullptr;
3424 }
3425 return rec.fHandle;
3426}
3427
3428std::unique_ptr<SkCanvas>
3429SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3430 const SkImageInfo& info, const Rec* rec) {
3431 if (!alloc || !supported_for_raster_canvas(info)) {
3432 return nullptr;
3433 }
3434
3435 SkBitmap bm;
3436 Handle hndl;
3437
3438 if (rec) {
3439 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3440 } else {
3441 hndl = alloc->allocBitmap(info, &bm);
3442 }
3443 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3444}