blob: 33d1deee60783807bd8db88a54a2267a47226f0a [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
bungemand3ebb482015-08-05 13:57:49 -07008#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"
joshualitt5f5a8d72015-02-25 14:09:45 -080017#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
msarettfbfa2582016-08-12 08:29:08 -070025#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070026#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070027#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000028#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070029#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000030#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080031#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000032#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070033#include "SkShadowPaintFilterCanvas.h"
34#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000035#include "SkSmallAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080036#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000037#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070038#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000039#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000040#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080041#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070042#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080045#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000046#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070047#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070048
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000049#endif
50
reede3b38ce2016-01-08 09:18:44 -080051#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
52
reedc83a2972015-07-16 07:40:45 -070053/*
54 * Return true if the drawing this rect would hit every pixels in the canvas.
55 *
56 * Returns false if
57 * - rect does not contain the canvas' bounds
58 * - paint is not fill
59 * - paint would blur or otherwise change the coverage of the rect
60 */
61bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
62 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070063 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
64 (int)kNone_ShaderOverrideOpacity,
65 "need_matching_enums0");
66 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
67 (int)kOpaque_ShaderOverrideOpacity,
68 "need_matching_enums1");
69 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
70 (int)kNotOpaque_ShaderOverrideOpacity,
71 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070072
73 const SkISize size = this->getBaseLayerSize();
74 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
75 if (!this->getClipStack()->quickContains(bounds)) {
76 return false;
77 }
78
79 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070080 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070081 return false; // conservative
82 }
halcanaryc5769b22016-08-10 07:13:21 -070083
84 SkRect devRect;
85 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
86 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070087 return false;
88 }
89 }
90
91 if (paint) {
92 SkPaint::Style paintStyle = paint->getStyle();
93 if (!(paintStyle == SkPaint::kFill_Style ||
94 paintStyle == SkPaint::kStrokeAndFill_Style)) {
95 return false;
96 }
97 if (paint->getMaskFilter() || paint->getLooper()
98 || paint->getPathEffect() || paint->getImageFilter()) {
99 return false; // conservative
100 }
101 }
102 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
103}
104
105///////////////////////////////////////////////////////////////////////////////////////////////////
106
reedd990e2f2014-12-22 11:58:30 -0800107static bool gIgnoreSaveLayerBounds;
108void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
109 gIgnoreSaveLayerBounds = ignore;
110}
111bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
112 return gIgnoreSaveLayerBounds;
113}
114
reed0acf1b42014-12-22 16:12:38 -0800115static bool gTreatSpriteAsBitmap;
116void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
117 gTreatSpriteAsBitmap = spriteAsBitmap;
118}
119bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
120 return gTreatSpriteAsBitmap;
121}
122
reed@google.comda17f752012-08-16 18:27:05 +0000123// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124//#define SK_TRACE_SAVERESTORE
125
126#ifdef SK_TRACE_SAVERESTORE
127 static int gLayerCounter;
128 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
129 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
130
131 static int gRecCounter;
132 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
133 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
134
135 static int gCanvasCounter;
136 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
137 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
138#else
139 #define inc_layer()
140 #define dec_layer()
141 #define inc_rec()
142 #define dec_rec()
143 #define inc_canvas()
144 #define dec_canvas()
145#endif
146
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000147typedef SkTLazy<SkPaint> SkLazyPaint;
148
reedc83a2972015-07-16 07:40:45 -0700149void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000150 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700151 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
152 ? SkSurface::kDiscard_ContentChangeMode
153 : SkSurface::kRetain_ContentChangeMode);
154 }
155}
156
157void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
158 ShaderOverrideOpacity overrideOpacity) {
159 if (fSurfaceBase) {
160 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
161 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
162 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
163 // and therefore we don't care which mode we're in.
164 //
165 if (fSurfaceBase->outstandingImageSnapshot()) {
166 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
167 mode = SkSurface::kDiscard_ContentChangeMode;
168 }
169 }
170 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000171 }
172}
173
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000176/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 The clip/matrix/proc are fields that reflect the top of the save/restore
178 stack. Whenever the canvas changes, it marks a dirty flag, and then before
179 these are used (assuming we're not on a layer) we rebuild these cache
180 values: they reflect the top of the save stack, but translated and clipped
181 by the device's XY offset and bitmap-bounds.
182*/
183struct DeviceCM {
184 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000185 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000186 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000187 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700188 const SkMatrix* fMatrix;
189 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700190 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191
reed96e657d2015-03-10 17:30:07 -0700192 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700193 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700194 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700195 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700196 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700197 {
reed2c9e2002016-07-25 08:05:22 -0700198 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000199 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700200 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000201 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000203 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700204 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700205 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000206 }
reed@google.com4b226022011-01-11 18:32:13 +0000207
mtkleinfeaadee2015-04-08 11:25:48 -0700208 void reset(const SkIRect& bounds) {
209 SkASSERT(!fPaint);
210 SkASSERT(!fNext);
211 SkASSERT(fDevice);
212 fClip.setRect(bounds);
213 }
214
reed@google.com045e62d2011-10-24 12:19:46 +0000215 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700216 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000217 int x = fDevice->getOrigin().x();
218 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 int width = fDevice->width();
220 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000221
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 if ((x | y) == 0) {
223 fMatrix = &totalMatrix;
224 fClip = totalClip;
225 } else {
226 fMatrixStorage = totalMatrix;
227 fMatrixStorage.postTranslate(SkIntToScalar(-x),
228 SkIntToScalar(-y));
229 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000230
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 totalClip.translate(-x, -y, &fClip);
232 }
233
reed@google.com045e62d2011-10-24 12:19:46 +0000234 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235
236 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000239 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 SkRegion::kDifference_Op);
241 }
reed@google.com4b226022011-01-11 18:32:13 +0000242
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243#ifdef SK_DEBUG
244 if (!fClip.isEmpty()) {
245 SkIRect deviceR;
246 deviceR.set(0, 0, width, height);
247 SkASSERT(deviceR.contains(fClip.getBounds()));
248 }
249#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000250 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251};
252
253/* This is the record we keep for each save/restore level in the stack.
254 Since a level optionally copies the matrix and/or stack, we have pointers
255 for these fields. If the value is copied for this level, the copy is
256 stored in the ...Storage field, and the pointer points to that. If the
257 value is not copied for this level, we ignore ...Storage, and just point
258 at the corresponding value in the previous level in the stack.
259*/
260class SkCanvas::MCRec {
261public:
reed1f836ee2014-07-07 07:49:34 -0700262 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700263 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 /* If there are any layers in the stack, this points to the top-most
265 one that is at or below this level in the stack (so we know what
266 bitmap/device to draw into from this level. This value is NOT
267 reference counted, since the real owner is either our fLayer field,
268 or a previous one in a lower level.)
269 */
reed2ff1fce2014-12-11 07:07:37 -0800270 DeviceCM* fTopLayer;
271 SkRasterClip fRasterClip;
272 SkMatrix fMatrix;
273 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274
vjiaoblacke5de1302016-07-13 14:05:28 -0700275 // This is the current cumulative depth (aggregate of all done translateZ calls)
276 SkScalar fCurDrawDepth;
277
reedd9544982014-09-09 18:46:22 -0700278 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700279 fFilter = nullptr;
280 fLayer = nullptr;
281 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800282 fMatrix.reset();
283 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700284 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700285
reedd9544982014-09-09 18:46:22 -0700286 // don't bother initializing fNext
287 inc_rec();
288 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700289 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
290 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700291 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700292 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700293 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800294 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700295
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 // don't bother initializing fNext
297 inc_rec();
298 }
299 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000300 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700301 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302 dec_rec();
303 }
mtkleinfeaadee2015-04-08 11:25:48 -0700304
305 void reset(const SkIRect& bounds) {
306 SkASSERT(fLayer);
307 SkASSERT(fDeferredSaveCount == 0);
308
309 fMatrix.reset();
310 fRasterClip.setRect(bounds);
311 fLayer->reset(bounds);
312 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313};
314
reed02f9ed72016-09-06 09:06:18 -0700315static SkIRect compute_device_bounds(SkBaseDevice* device) {
316 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
317 device->width(), device->height());
318}
319
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320class SkDrawIter : public SkDraw {
321public:
reed3aafe112016-08-18 12:45:34 -0700322 SkDrawIter(SkCanvas* canvas) {
junov@google.com4370aed2012-01-18 16:21:08 +0000323 canvas = canvas->canvasForDrawIter();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324 canvas->updateDeviceCMCache();
325
reed687fa1c2015-04-07 08:00:56 -0700326 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700328
329 fMultiDeviceCS = nullptr;
330 if (fCurrLayer->fNext) {
331 fMultiDeviceCS = canvas->fClipStack;
332 fMultiDeviceCS->save();
333 }
334 }
335
336 ~SkDrawIter() {
337 if (fMultiDeviceCS) {
338 fMultiDeviceCS->restore();
339 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 }
reed@google.com4b226022011-01-11 18:32:13 +0000341
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700343 if (fMultiDeviceCS && fDevice) {
344 // remove the previous device's bounds
reed73603f32016-09-20 08:42:38 -0700345 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), SkCanvas::kDifference_Op);
reed02f9ed72016-09-06 09:06:18 -0700346 }
347
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700349 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
350 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 }
352
reed@google.comf68c5e22012-02-24 16:38:58 +0000353 const DeviceCM* rec = fCurrLayer;
354 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355
356 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000357 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700359 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700360 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700361 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000363 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364
365 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700366 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000367
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368 return true;
369 }
370 return false;
371 }
reed@google.com4b226022011-01-11 18:32:13 +0000372
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000373 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700374 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000375 int getX() const { return fDevice->getOrigin().x(); }
376 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000379
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381 const DeviceCM* fCurrLayer;
382 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700383 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384
385 typedef SkDraw INHERITED;
386};
387
388/////////////////////////////////////////////////////////////////////////////
389
reeddbc3cef2015-04-29 12:18:57 -0700390static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
391 return lazy->isValid() ? lazy->get() : lazy->set(orig);
392}
393
394/**
395 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700396 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700397 */
reedd053ce92016-03-22 10:17:23 -0700398static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700399 SkImageFilter* imgf = paint.getImageFilter();
400 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700401 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700402 }
403
reedd053ce92016-03-22 10:17:23 -0700404 SkColorFilter* imgCFPtr;
405 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700406 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700407 }
reedd053ce92016-03-22 10:17:23 -0700408 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700409
410 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700411 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700412 // there is no existing paint colorfilter, so we can just return the imagefilter's
413 return imgCF;
414 }
415
416 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
417 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700418 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700419}
420
senorblanco87e066e2015-10-28 11:23:36 -0700421/**
422 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
423 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
424 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
425 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
426 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
427 * conservative "effective" bounds based on the settings in the paint... with one exception. This
428 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
429 * deliberately ignored.
430 */
431static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
432 const SkRect& rawBounds,
433 SkRect* storage) {
434 SkPaint tmpUnfiltered(paint);
435 tmpUnfiltered.setImageFilter(nullptr);
436 if (tmpUnfiltered.canComputeFastBounds()) {
437 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
438 } else {
439 return rawBounds;
440 }
441}
442
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443class AutoDrawLooper {
444public:
senorblanco87e066e2015-10-28 11:23:36 -0700445 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
446 // paint. It's used to determine the size of the offscreen layer for filters.
447 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700448 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700449 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000450 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800451#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800453#else
454 fFilter = nullptr;
455#endif
reed4a8126e2014-09-22 07:29:03 -0700456 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000457 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700458 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000459 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460
reedd053ce92016-03-22 10:17:23 -0700461 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700462 if (simplifiedCF) {
463 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700464 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700465 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700466 fPaint = paint;
467 }
468
469 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700470 /**
471 * We implement ImageFilters for a given draw by creating a layer, then applying the
472 * imagefilter to the pixels of that layer (its backing surface/image), and then
473 * we call restore() to xfer that layer to the main canvas.
474 *
475 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
476 * 2. Generate the src pixels:
477 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
478 * return (fPaint). We then draw the primitive (using srcover) into a cleared
479 * buffer/surface.
480 * 3. Restore the layer created in #1
481 * The imagefilter is passed the buffer/surface from the layer (now filled with the
482 * src pixels of the primitive). It returns a new "filtered" buffer, which we
483 * draw onto the previous layer using the xfermode from the original paint.
484 */
reed@google.com8926b162012-03-23 15:36:36 +0000485 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700486 tmp.setImageFilter(fPaint->getImageFilter());
reedcfb6bdf2016-03-29 11:32:50 -0700487 tmp.setXfermode(sk_ref_sp(fPaint->getXfermode()));
senorblanco87e066e2015-10-28 11:23:36 -0700488 SkRect storage;
489 if (rawBounds) {
490 // Make rawBounds include all paint outsets except for those due to image filters.
491 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
492 }
reedbfd5f172016-01-07 11:28:08 -0800493 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700494 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700495 fTempLayerForImageFilter = true;
496 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000497 }
498
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000499 if (SkDrawLooper* looper = paint.getLooper()) {
500 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
501 looper->contextSize());
502 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000503 fIsSimple = false;
504 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700505 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000506 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700507 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000508 }
509 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000510
reed@android.com8a1c16f2008-12-17 15:59:43 +0000511 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700512 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000513 fCanvas->internalRestore();
514 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000515 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000517
reed@google.com4e2b3d32011-04-07 14:18:59 +0000518 const SkPaint& paint() const {
519 SkASSERT(fPaint);
520 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000522
reed@google.com129ec222012-05-15 13:24:09 +0000523 bool next(SkDrawFilter::Type drawType) {
524 if (fDone) {
525 return false;
526 } else if (fIsSimple) {
527 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000528 return !fPaint->nothingToDraw();
529 } else {
530 return this->doNext(drawType);
531 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000532 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000533
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534private:
reeddbc3cef2015-04-29 12:18:57 -0700535 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
536 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000537 SkCanvas* fCanvas;
538 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000539 SkDrawFilter* fFilter;
540 const SkPaint* fPaint;
541 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700542 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000543 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000544 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000545 SkDrawLooper::Context* fLooperContext;
546 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000547
548 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549};
550
reed@google.com129ec222012-05-15 13:24:09 +0000551bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700552 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000553 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700554 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000555
reeddbc3cef2015-04-29 12:18:57 -0700556 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
557 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000558
reed5c476fb2015-04-20 08:04:21 -0700559 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700560 paint->setImageFilter(nullptr);
561 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000562 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000563
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000564 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000565 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000566 return false;
567 }
568 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000569 if (!fFilter->filter(paint, drawType)) {
570 fDone = true;
571 return false;
572 }
halcanary96fcdcc2015-08-27 07:41:13 -0700573 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000574 // no looper means we only draw once
575 fDone = true;
576 }
577 }
578 fPaint = paint;
579
580 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000581 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000582 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000583 }
584
585 // call this after any possible paint modifiers
586 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700587 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000588 return false;
589 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000590 return true;
591}
592
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593////////// macros to place around the internal draw calls //////////////////
594
reed3aafe112016-08-18 12:45:34 -0700595#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
596 this->predrawNotify(); \
597 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
598 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800599 SkDrawIter iter(this);
600
601
reed@google.com8926b162012-03-23 15:36:36 +0000602#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000603 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700604 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000605 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000606 SkDrawIter iter(this);
607
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000608#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000609 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700610 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000611 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000613
reedc83a2972015-07-16 07:40:45 -0700614#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
615 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700616 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700617 while (looper.next(type)) { \
618 SkDrawIter iter(this);
619
reed@google.com4e2b3d32011-04-07 14:18:59 +0000620#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000621
622////////////////////////////////////////////////////////////////////////////
623
msarettfbfa2582016-08-12 08:29:08 -0700624static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
625 if (bounds.isEmpty()) {
626 return SkRect::MakeEmpty();
627 }
628
629 // Expand bounds out by 1 in case we are anti-aliasing. We store the
630 // bounds as floats to enable a faster quick reject implementation.
631 SkRect dst;
632 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
633 return dst;
634}
635
mtkleinfeaadee2015-04-08 11:25:48 -0700636void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
637 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700638 fClipStack->reset();
639 fMCRec->reset(bounds);
640
641 // We're peering through a lot of structs here. Only at this scope do we
642 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
643 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700644 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700645 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700646}
647
reedd9544982014-09-09 18:46:22 -0700648SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800649 if (device && device->forceConservativeRasterClip()) {
650 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
651 }
652 // Since init() is only called once by our constructors, it is safe to perform this
653 // const-cast.
654 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
655
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000656 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000657 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700658 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800659 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700660 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700661#ifdef SK_EXPERIMENTAL_SHADOWING
662 fLights = nullptr;
663#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664
halcanary385fe4d2015-08-26 13:07:48 -0700665 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700666
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700668 new (fMCRec) MCRec(fConservativeRasterClip);
msarett9637ea92016-08-18 14:03:30 -0700669 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670
reeda499f902015-05-01 09:34:31 -0700671 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
672 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700673 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700674 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700675
reed@android.com8a1c16f2008-12-17 15:59:43 +0000676 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677
halcanary96fcdcc2015-08-27 07:41:13 -0700678 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000679
reedf92c8662014-08-18 08:02:43 -0700680 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700681 // The root device and the canvas should always have the same pixel geometry
682 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700683 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800684 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700685 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700686 }
msarettfbfa2582016-08-12 08:29:08 -0700687
reedf92c8662014-08-18 08:02:43 -0700688 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000689}
690
reed@google.comcde92112011-07-06 20:00:52 +0000691SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000692 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700693 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800694 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000695{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000696 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000697
halcanary96fcdcc2015-08-27 07:41:13 -0700698 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000699}
700
reedd9544982014-09-09 18:46:22 -0700701static SkBitmap make_nopixels(int width, int height) {
702 SkBitmap bitmap;
703 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
704 return bitmap;
705}
706
707class SkNoPixelsBitmapDevice : public SkBitmapDevice {
708public:
robertphillipsfcf78292015-06-19 11:49:52 -0700709 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
710 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800711 {
712 this->setOrigin(bounds.x(), bounds.y());
713 }
reedd9544982014-09-09 18:46:22 -0700714
715private:
piotaixrb5fae932014-09-24 13:03:30 -0700716
reedd9544982014-09-09 18:46:22 -0700717 typedef SkBitmapDevice INHERITED;
718};
719
reed96a857e2015-01-25 10:33:58 -0800720SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000721 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800722 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800723 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000724{
725 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700726
halcanary385fe4d2015-08-26 13:07:48 -0700727 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
728 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700729}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000730
reed78e27682014-11-19 08:04:34 -0800731SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700732 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700733 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800734 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700735{
736 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700737
halcanary385fe4d2015-08-26 13:07:48 -0700738 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700739}
740
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000741SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000742 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700743 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800744 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000745{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700747
reedd9544982014-09-09 18:46:22 -0700748 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749}
750
robertphillipsfcf78292015-06-19 11:49:52 -0700751SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
752 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700753 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800754 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700755{
756 inc_canvas();
757
758 this->init(device, flags);
759}
760
reed4a8126e2014-09-22 07:29:03 -0700761SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700762 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700763 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800764 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700765{
766 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700767
halcanary385fe4d2015-08-26 13:07:48 -0700768 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700769 this->init(device, kDefault_InitFlags);
770}
reed29c857d2014-09-21 10:25:07 -0700771
reed4a8126e2014-09-22 07:29:03 -0700772SkCanvas::SkCanvas(const SkBitmap& bitmap)
773 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
774 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800775 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700776{
777 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700778
halcanary385fe4d2015-08-26 13:07:48 -0700779 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700780 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781}
782
783SkCanvas::~SkCanvas() {
784 // free up the contents of our deque
785 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000786
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787 this->internalRestore(); // restore the last, since we're going away
788
halcanary385fe4d2015-08-26 13:07:48 -0700789 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000790
reed@android.com8a1c16f2008-12-17 15:59:43 +0000791 dec_canvas();
792}
793
fmalita53d9f1c2016-01-25 06:23:54 -0800794#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000795SkDrawFilter* SkCanvas::getDrawFilter() const {
796 return fMCRec->fFilter;
797}
798
799SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700800 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
802 return filter;
803}
fmalita77650002016-01-21 18:47:11 -0800804#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000806SkMetaData& SkCanvas::getMetaData() {
807 // metadata users are rare, so we lazily allocate it. If that changes we
808 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700809 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000810 fMetaData = new SkMetaData;
811 }
812 return *fMetaData;
813}
814
reed@android.com8a1c16f2008-12-17 15:59:43 +0000815///////////////////////////////////////////////////////////////////////////////
816
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000817void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700818 this->onFlush();
819}
820
821void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000822 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000823 if (device) {
824 device->flush();
825 }
826}
827
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000828SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000829 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000830 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
831}
832
senorblancoafc7cce2016-02-02 18:44:15 -0800833SkIRect SkCanvas::getTopLayerBounds() const {
834 SkBaseDevice* d = this->getTopDevice();
835 if (!d) {
836 return SkIRect::MakeEmpty();
837 }
838 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
839}
840
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000841SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000842 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000843 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844 SkASSERT(rec && rec->fLayer);
845 return rec->fLayer->fDevice;
846}
847
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000848SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000849 if (updateMatrixClip) {
850 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
851 }
reed@google.com9266fed2011-03-30 00:18:03 +0000852 return fMCRec->fTopLayer->fDevice;
853}
854
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000855bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700856 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000857 return false;
858 }
859
860 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) {
halcanary96fcdcc2015-08-27 07:41:13 -0700877 bitmap->setPixelRef(nullptr);
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 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000906 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800907
reed96472de2014-12-10 09:53:42 -0800908 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
909 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000910 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000911 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000912
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000913 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800914 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000915}
916
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000917bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700918 SkAutoPixmapUnlock unlocker;
919 if (bitmap.requestLock(&unlocker)) {
920 const SkPixmap& pm = unlocker.pixmap();
921 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000922 }
923 return false;
924}
925
926bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
927 int x, int y) {
928 switch (origInfo.colorType()) {
929 case kUnknown_SkColorType:
930 case kIndex_8_SkColorType:
931 return false;
932 default:
933 break;
934 }
halcanary96fcdcc2015-08-27 07:41:13 -0700935 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000936 return false;
937 }
938
939 const SkISize size = this->getBaseLayerSize();
940 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
941 if (!target.intersect(0, 0, size.width(), size.height())) {
942 return false;
943 }
944
945 SkBaseDevice* device = this->getDevice();
946 if (!device) {
947 return false;
948 }
949
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000950 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700951 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000952
953 // if x or y are negative, then we have to adjust pixels
954 if (x > 0) {
955 x = 0;
956 }
957 if (y > 0) {
958 y = 0;
959 }
960 // here x,y are either 0 or negative
961 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
962
reed4af35f32014-06-27 17:47:49 -0700963 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700964 const bool completeOverwrite = info.dimensions() == size;
965 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700966
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000967 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000968 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000969}
reed@google.com51df9e32010-12-23 19:29:18 +0000970
junov@google.com4370aed2012-01-18 16:21:08 +0000971SkCanvas* SkCanvas::canvasForDrawIter() {
972 return this;
973}
974
reed@android.com8a1c16f2008-12-17 15:59:43 +0000975//////////////////////////////////////////////////////////////////////////////
976
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977void SkCanvas::updateDeviceCMCache() {
978 if (fDeviceCMDirty) {
979 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700980 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000982
halcanary96fcdcc2015-08-27 07:41:13 -0700983 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700984 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000985 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000986 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987 do {
reedde6c5312016-09-02 12:10:07 -0700988 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700989 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000990 }
991 fDeviceCMDirty = false;
992 }
993}
994
reed@android.com8a1c16f2008-12-17 15:59:43 +0000995///////////////////////////////////////////////////////////////////////////////
996
reed2ff1fce2014-12-11 07:07:37 -0800997void SkCanvas::checkForDeferredSave() {
998 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800999 this->doSave();
1000 }
1001}
1002
reedf0090cb2014-11-26 08:55:51 -08001003int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -08001004#ifdef SK_DEBUG
1005 int count = 0;
1006 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1007 for (;;) {
1008 const MCRec* rec = (const MCRec*)iter.next();
1009 if (!rec) {
1010 break;
1011 }
1012 count += 1 + rec->fDeferredSaveCount;
1013 }
1014 SkASSERT(count == fSaveCount);
1015#endif
1016 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001017}
1018
1019int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001020 fSaveCount += 1;
1021 fMCRec->fDeferredSaveCount += 1;
1022 return this->getSaveCount() - 1; // return our prev value
1023}
1024
1025void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001026 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001027
1028 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1029 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001030 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001031}
1032
1033void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001034 if (fMCRec->fDeferredSaveCount > 0) {
1035 SkASSERT(fSaveCount > 1);
1036 fSaveCount -= 1;
1037 fMCRec->fDeferredSaveCount -= 1;
1038 } else {
1039 // check for underflow
1040 if (fMCStack.count() > 1) {
1041 this->willRestore();
1042 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001043 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001044 this->internalRestore();
1045 this->didRestore();
1046 }
reedf0090cb2014-11-26 08:55:51 -08001047 }
1048}
1049
1050void SkCanvas::restoreToCount(int count) {
1051 // sanity check
1052 if (count < 1) {
1053 count = 1;
1054 }
mtkleinf0f14112014-12-12 08:46:25 -08001055
reedf0090cb2014-11-26 08:55:51 -08001056 int n = this->getSaveCount() - count;
1057 for (int i = 0; i < n; ++i) {
1058 this->restore();
1059 }
1060}
1061
reed2ff1fce2014-12-11 07:07:37 -08001062void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001063 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001064 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001065 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001066
reed687fa1c2015-04-07 08:00:56 -07001067 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068}
1069
reed4960eee2015-12-18 07:09:18 -08001070bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001071 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072}
1073
reed4960eee2015-12-18 07:09:18 -08001074bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001075 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001076 SkIRect clipBounds;
1077 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001078 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001079 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001080
reed96e657d2015-03-10 17:30:07 -07001081 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1082
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001083 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001084 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001085 if (bounds && !imageFilter->canComputeFastBounds()) {
1086 bounds = nullptr;
1087 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001088 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001089 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001090 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001091 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001092
reed96e657d2015-03-10 17:30:07 -07001093 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094 r.roundOut(&ir);
1095 // early exit if the layer's bounds are clipped out
1096 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001097 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001098 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001099 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001100 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001101 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001102 }
1103 } else { // no user bounds, so just use the clip
1104 ir = clipBounds;
1105 }
reed180aec42015-03-11 10:39:04 -07001106 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107
reed4960eee2015-12-18 07:09:18 -08001108 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001109 // Simplify the current clips since they will be applied properly during restore()
reed73603f32016-09-20 08:42:38 -07001110 fClipStack->clipDevRect(ir, kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001111 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001112 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001113 }
1114
1115 if (intersection) {
1116 *intersection = ir;
1117 }
1118 return true;
1119}
1120
reed4960eee2015-12-18 07:09:18 -08001121
reed4960eee2015-12-18 07:09:18 -08001122int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1123 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001124}
1125
reed70ee31b2015-12-10 13:44:45 -08001126int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001127 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1128}
1129
1130int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1131 SaveLayerRec rec(origRec);
1132 if (gIgnoreSaveLayerBounds) {
1133 rec.fBounds = nullptr;
1134 }
1135 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1136 fSaveCount += 1;
1137 this->internalSaveLayer(rec, strategy);
1138 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001139}
1140
reeda2217ef2016-07-20 06:04:34 -07001141void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1142 SkBaseDevice* dst, const SkMatrix& ctm,
1143 const SkClipStack* clipStack) {
1144 SkDraw draw;
1145 SkRasterClip rc;
1146 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1147 if (!dst->accessPixels(&draw.fDst)) {
1148 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001149 }
reeda2217ef2016-07-20 06:04:34 -07001150 draw.fMatrix = &SkMatrix::I();
1151 draw.fRC = &rc;
1152 draw.fClipStack = clipStack;
1153 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001154
1155 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001156 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001157
1158 int x = src->getOrigin().x() - dst->getOrigin().x();
1159 int y = src->getOrigin().y() - dst->getOrigin().y();
1160 auto special = src->snapSpecial();
1161 if (special) {
1162 dst->drawSpecial(draw, special.get(), x, y, p);
1163 }
robertphillips7354a4b2015-12-16 05:08:27 -08001164}
reed70ee31b2015-12-10 13:44:45 -08001165
reed129ed1c2016-02-22 06:42:31 -08001166static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1167 const SkPaint* paint) {
1168 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1169 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001170 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001171 const bool hasImageFilter = paint && paint->getImageFilter();
1172
1173 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1174 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1175 // force to L32
1176 return SkImageInfo::MakeN32(w, h, alphaType);
1177 } else {
1178 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001179 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001180 }
1181}
1182
reed4960eee2015-12-18 07:09:18 -08001183void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1184 const SkRect* bounds = rec.fBounds;
1185 const SkPaint* paint = rec.fPaint;
1186 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1187
reed8c30a812016-04-20 16:36:51 -07001188 SkLazyPaint lazyP;
1189 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1190 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001191 SkMatrix remainder;
1192 SkSize scale;
1193 /*
1194 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1195 * but they do handle scaling. To accommodate this, we do the following:
1196 *
1197 * 1. Stash off the current CTM
1198 * 2. Decompose the CTM into SCALE and REMAINDER
1199 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1200 * contains the REMAINDER
1201 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1202 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1203 * of the original imagefilter, and draw that (via drawSprite)
1204 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1205 *
1206 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1207 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1208 */
reed96a04f32016-04-25 09:25:15 -07001209 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001210 stashedMatrix.decomposeScale(&scale, &remainder))
1211 {
1212 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1213 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1214 SkPaint* p = lazyP.set(*paint);
1215 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1216 SkFilterQuality::kLow_SkFilterQuality,
1217 sk_ref_sp(imageFilter)));
1218 imageFilter = p->getImageFilter();
1219 paint = p;
1220 }
reed8c30a812016-04-20 16:36:51 -07001221
junov@chromium.orga907ac32012-02-24 21:54:07 +00001222 // do this before we create the layer. We don't call the public save() since
1223 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001224 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001225
1226 fDeviceCMDirty = true;
1227
1228 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001229 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001230 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001231 }
1232
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001233 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1234 // the clipRectBounds() call above?
1235 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001236 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001237 }
1238
reed4960eee2015-12-18 07:09:18 -08001239 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001240 SkPixelGeometry geo = fProps.pixelGeometry();
1241 if (paint) {
reed76033be2015-03-14 10:54:31 -07001242 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001243 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001244 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001245 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001246 }
1247 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001248
robertphillips5139e502016-07-19 05:10:40 -07001249 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001250 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001251 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001252 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001253 }
reedb2db8982014-11-13 12:41:02 -08001254
robertphillips5139e502016-07-19 05:10:40 -07001255 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001256 paint);
1257
robertphillips5139e502016-07-19 05:10:40 -07001258 SkAutoTUnref<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001259 {
reed70ee31b2015-12-10 13:44:45 -08001260 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001261 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001262 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001263 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
reedcd4051e2016-07-15 09:41:26 -07001264 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001265 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1266 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001267 SkErrorInternals::SetError(kInternalError_SkError,
1268 "Unable to create device for layer.");
1269 return;
reed61f501f2015-04-29 08:34:00 -07001270 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001271 }
robertphillips5139e502016-07-19 05:10:40 -07001272 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001273
robertphillips5139e502016-07-19 05:10:40 -07001274 DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275
1276 layer->fNext = fMCRec->fTopLayer;
1277 fMCRec->fLayer = layer;
1278 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001279
1280 if (rec.fBackdrop) {
1281 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice,
1282 fMCRec->fMatrix, this->getClipStack());
1283 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001284}
1285
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001286int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001287 if (0xFF == alpha) {
1288 return this->saveLayer(bounds, nullptr);
1289 } else {
1290 SkPaint tmpPaint;
1291 tmpPaint.setAlpha(alpha);
1292 return this->saveLayer(bounds, &tmpPaint);
1293 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001294}
1295
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296void SkCanvas::internalRestore() {
1297 SkASSERT(fMCStack.count() != 0);
1298
1299 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300
reed687fa1c2015-04-07 08:00:56 -07001301 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001302
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001303 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001304 DeviceCM* layer = fMCRec->fLayer; // may be null
1305 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001306 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307
1308 // now do the normal restore()
1309 fMCRec->~MCRec(); // balanced in save()
1310 fMCStack.pop_back();
1311 fMCRec = (MCRec*)fMCStack.back();
1312
1313 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1314 since if we're being recorded, we don't want to record this (the
1315 recorder will have already recorded the restore).
1316 */
bsalomon49f085d2014-09-05 13:34:00 -07001317 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001319 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001320 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001321 // restore what we smashed in internalSaveLayer
1322 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001323 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001325 delete layer;
reedb679ca82015-04-07 04:40:48 -07001326 } else {
1327 // we're at the root
reeda499f902015-05-01 09:34:31 -07001328 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001329 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001330 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001331 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001332 }
msarettfbfa2582016-08-12 08:29:08 -07001333
1334 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001335 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001336 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1337 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338}
1339
reede8f30622016-03-23 18:59:25 -07001340sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001341 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001342 props = &fProps;
1343 }
1344 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001345}
1346
reede8f30622016-03-23 18:59:25 -07001347sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001348 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001349 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001350}
1351
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001352SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001353 return this->onImageInfo();
1354}
1355
1356SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001357 SkBaseDevice* dev = this->getDevice();
1358 if (dev) {
1359 return dev->imageInfo();
1360 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001361 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001362 }
1363}
1364
brianosman898235c2016-04-06 07:38:23 -07001365bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001366 return this->onGetProps(props);
1367}
1368
1369bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001370 SkBaseDevice* dev = this->getDevice();
1371 if (dev) {
1372 if (props) {
1373 *props = fProps;
1374 }
1375 return true;
1376 } else {
1377 return false;
1378 }
1379}
1380
reed6ceeebd2016-03-09 14:26:26 -08001381#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001382const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001383 SkPixmap pmap;
reed6ceeebd2016-03-09 14:26:26 -08001384 if (this->peekPixels(&pmap)) {
1385 if (info) {
1386 *info = pmap.info();
1387 }
1388 if (rowBytes) {
1389 *rowBytes = pmap.rowBytes();
1390 }
1391 return pmap.addr();
reed884e97c2015-05-26 11:31:54 -07001392 }
reed6ceeebd2016-03-09 14:26:26 -08001393 return nullptr;
1394}
1395#endif
1396
1397bool SkCanvas::peekPixels(SkPixmap* pmap) {
1398 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001399}
1400
reed884e97c2015-05-26 11:31:54 -07001401bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001402 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001403 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001404}
1405
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001406void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001407 SkPixmap pmap;
1408 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001409 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001410 }
1411 if (info) {
1412 *info = pmap.info();
1413 }
1414 if (rowBytes) {
1415 *rowBytes = pmap.rowBytes();
1416 }
1417 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001418 *origin = this->getTopDevice(false)->getOrigin();
1419 }
reed884e97c2015-05-26 11:31:54 -07001420 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001421}
1422
reed884e97c2015-05-26 11:31:54 -07001423bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001424 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001425 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001426}
1427
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429
reed7503d602016-07-15 14:23:29 -07001430void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001432 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433 paint = &tmp;
1434 }
reed@google.com4b226022011-01-11 18:32:13 +00001435
reed@google.com8926b162012-03-23 15:36:36 +00001436 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001437
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001439 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001440 paint = &looper.paint();
1441 SkImageFilter* filter = paint->getImageFilter();
1442 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
senorblancof35566e2016-04-18 10:32:02 -07001443 if (filter) {
reeda2217ef2016-07-20 06:04:34 -07001444 dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001445 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001446 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001447 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448 }
reeda2217ef2016-07-20 06:04:34 -07001449
reed@google.com4e2b3d32011-04-07 14:18:59 +00001450 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001451}
1452
reed32704672015-12-16 08:27:10 -08001453/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001454
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001455void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001456 if (dx || dy) {
1457 this->checkForDeferredSave();
1458 fDeviceCMDirty = true;
1459 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001460
reedfe69b502016-09-12 06:31:48 -07001461 // Translate shouldn't affect the is-scale-translateness of the matrix.
1462 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001463
reedfe69b502016-09-12 06:31:48 -07001464 this->didTranslate(dx,dy);
1465 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466}
1467
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001468void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001469 SkMatrix m;
1470 m.setScale(sx, sy);
1471 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001472}
1473
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001474void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001475 SkMatrix m;
1476 m.setRotate(degrees);
1477 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001478}
1479
bungeman7438bfc2016-07-12 15:01:19 -07001480void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1481 SkMatrix m;
1482 m.setRotate(degrees, px, py);
1483 this->concat(m);
1484}
1485
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001486void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001487 SkMatrix m;
1488 m.setSkew(sx, sy);
1489 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001490}
1491
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001492void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001493 if (matrix.isIdentity()) {
1494 return;
1495 }
1496
reed2ff1fce2014-12-11 07:07:37 -08001497 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001498 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001499 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001500 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001501 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001502}
1503
reed8c30a812016-04-20 16:36:51 -07001504void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001506 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001507 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001508}
1509
1510void SkCanvas::setMatrix(const SkMatrix& matrix) {
1511 this->checkForDeferredSave();
1512 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001513 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001514}
1515
reed@android.com8a1c16f2008-12-17 15:59:43 +00001516void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001517 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001518}
1519
vjiaoblack95302da2016-07-21 10:25:54 -07001520#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001521void SkCanvas::translateZ(SkScalar z) {
1522 this->checkForDeferredSave();
1523 this->fMCRec->fCurDrawDepth += z;
1524 this->didTranslateZ(z);
1525}
1526
1527SkScalar SkCanvas::getZ() const {
1528 return this->fMCRec->fCurDrawDepth;
1529}
1530
vjiaoblack95302da2016-07-21 10:25:54 -07001531void SkCanvas::setLights(sk_sp<SkLights> lights) {
1532 this->fLights = lights;
1533}
1534
1535sk_sp<SkLights> SkCanvas::getLights() const {
1536 return this->fLights;
1537}
1538#endif
1539
reed@android.com8a1c16f2008-12-17 15:59:43 +00001540//////////////////////////////////////////////////////////////////////////////
1541
reed73603f32016-09-20 08:42:38 -07001542void SkCanvas::clipRect(const SkRect& rect, ClipOp op, bool doAA) {
reed2d1afab2016-06-29 14:33:11 -07001543 if (!fAllowSoftClip) {
1544 doAA = false;
1545 }
1546
reed2ff1fce2014-12-11 07:07:37 -08001547 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001548 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1549 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001550}
1551
reed73603f32016-09-20 08:42:38 -07001552void SkCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) {
reed74467162016-06-30 08:15:35 -07001553 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate();
reedc64eff52015-11-21 12:39:45 -08001554 SkRect devR;
reed74467162016-06-30 08:15:35 -07001555 if (isScaleTrans) {
halcanaryc5769b22016-08-10 07:13:21 -07001556 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reedc64eff52015-11-21 12:39:45 -08001557 }
bsalomonac8cabd2015-11-20 18:53:07 -08001558
reed73603f32016-09-20 08:42:38 -07001559 if (kIntersect_Op == op && kHard_ClipEdgeStyle == edgeStyle && isScaleTrans) {
reedc64eff52015-11-21 12:39:45 -08001560 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1561#if 0
1562 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1563 rect.left(), rect.top(), rect.right(), rect.bottom());
1564#endif
1565 return;
1566 }
1567 }
1568
1569 AutoValidateClip avc(this);
1570
1571 fDeviceCMDirty = true;
reedc64eff52015-11-21 12:39:45 -08001572
reed74467162016-06-30 08:15:35 -07001573 if (isScaleTrans) {
reedc64eff52015-11-21 12:39:45 -08001574 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1575 fClipStack->clipDevRect(devR, op, isAA);
reed73603f32016-09-20 08:42:38 -07001576 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), (SkRegion::Op)op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001577 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001578 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001579 // and clip against that, since it can handle any matrix. However, to
1580 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1581 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582 SkPath path;
1583
1584 path.addRect(rect);
bsalomonbdc335f2016-08-22 13:42:17 -07001585 path.setIsVolatile(true);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001586 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001587 }
msarettfbfa2582016-08-12 08:29:08 -07001588
1589 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001590}
1591
reed73603f32016-09-20 08:42:38 -07001592void SkCanvas::clipRRect(const SkRRect& rrect, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001593 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001594 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001595 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001596 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1597 } else {
1598 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001599 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001600}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001601
reed73603f32016-09-20 08:42:38 -07001602void SkCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001603 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001604 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001605 AutoValidateClip avc(this);
1606
1607 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001608 if (!fAllowSoftClip) {
1609 edgeStyle = kHard_ClipEdgeStyle;
1610 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001611
reed687fa1c2015-04-07 08:00:56 -07001612 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001613
reed73603f32016-09-20 08:42:38 -07001614 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), (SkRegion::Op)op,
robertphillips125f19a2015-11-23 09:00:05 -08001615 kSoft_ClipEdgeStyle == edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001616 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001617 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001618 }
1619
1620 SkPath path;
1621 path.addRRect(rrect);
bsalomonbdc335f2016-08-22 13:42:17 -07001622 path.setIsVolatile(true);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001623 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001624 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001625}
1626
reed73603f32016-09-20 08:42:38 -07001627void SkCanvas::clipPath(const SkPath& path, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001628 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001629 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001630
1631 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1632 SkRect r;
1633 if (path.isRect(&r)) {
1634 this->onClipRect(r, op, edgeStyle);
1635 return;
1636 }
1637 SkRRect rrect;
1638 if (path.isOval(&r)) {
1639 rrect.setOval(r);
1640 this->onClipRRect(rrect, op, edgeStyle);
1641 return;
1642 }
1643 if (path.isRRect(&rrect)) {
1644 this->onClipRRect(rrect, op, edgeStyle);
1645 return;
1646 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001647 }
robertphillips39f05382015-11-24 09:30:12 -08001648
1649 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001650}
1651
reed73603f32016-09-20 08:42:38 -07001652void SkCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001653 AutoValidateClip avc(this);
1654
reed@android.com8a1c16f2008-12-17 15:59:43 +00001655 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001656 if (!fAllowSoftClip) {
1657 edgeStyle = kHard_ClipEdgeStyle;
1658 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001659
1660 SkPath devPath;
bsalomonbdc335f2016-08-22 13:42:17 -07001661 if (fMCRec->fMatrix.isIdentity()) {
1662 devPath = path;
1663 } else {
1664 path.transform(fMCRec->fMatrix, &devPath);
1665 devPath.setIsVolatile(true);
1666 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001667
reed@google.comfe701122011-11-08 19:41:23 +00001668 // Check if the transfomation, or the original path itself
1669 // made us empty. Note this can also happen if we contained NaN
1670 // values. computing the bounds detects this, and will set our
1671 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1672 if (devPath.getBounds().isEmpty()) {
1673 // resetting the path will remove any NaN or other wanky values
1674 // that might upset our scan converter.
1675 devPath.reset();
1676 }
1677
reed@google.com5c3d1472011-02-22 19:12:23 +00001678 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001679 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001680
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001681 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001682 bool clipIsAA = getClipStack()->asPath(&devPath);
1683 if (clipIsAA) {
1684 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001685 }
fmalita1a481fe2015-02-04 07:39:34 -08001686
reed73603f32016-09-20 08:42:38 -07001687 op = kReplace_Op;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001688 }
1689
reed73603f32016-09-20 08:42:38 -07001690 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), (SkRegion::Op)op, edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001691 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692}
1693
reed73603f32016-09-20 08:42:38 -07001694void SkCanvas::clipRegion(const SkRegion& rgn, ClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001695 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001696 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001697}
1698
reed73603f32016-09-20 08:42:38 -07001699void SkCanvas::onClipRegion(const SkRegion& rgn, ClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001700 AutoValidateClip avc(this);
1701
reed@android.com8a1c16f2008-12-17 15:59:43 +00001702 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001703
reed@google.com5c3d1472011-02-22 19:12:23 +00001704 // todo: signal fClipStack that we have a region, and therefore (I guess)
1705 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001706 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001707
reed73603f32016-09-20 08:42:38 -07001708 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001709 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001710}
1711
reed@google.com819c9212011-02-23 18:56:55 +00001712#ifdef SK_DEBUG
1713void SkCanvas::validateClip() const {
1714 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001715 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001716 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001717 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001718 return;
1719 }
1720
reed@google.com819c9212011-02-23 18:56:55 +00001721 SkIRect ir;
1722 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001723 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001724
reed687fa1c2015-04-07 08:00:56 -07001725 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001726 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001727 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001728 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001729 case SkClipStack::Element::kRect_Type:
1730 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001731 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001732 break;
1733 case SkClipStack::Element::kEmpty_Type:
1734 tmpClip.setEmpty();
1735 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001736 default: {
1737 SkPath path;
1738 element->asPath(&path);
reed73603f32016-09-20 08:42:38 -07001739 tmpClip.op(path, this->getTopLayerBounds(), (SkRegion::Op)element->getOp(),
1740 element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001741 break;
1742 }
reed@google.com819c9212011-02-23 18:56:55 +00001743 }
1744 }
reed@google.com819c9212011-02-23 18:56:55 +00001745}
1746#endif
1747
reed@google.com90c07ea2012-04-13 13:50:27 +00001748void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001749 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001750 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001751
halcanary96fcdcc2015-08-27 07:41:13 -07001752 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001753 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001754 }
1755}
1756
reed@google.com5c3d1472011-02-22 19:12:23 +00001757///////////////////////////////////////////////////////////////////////////////
1758
reed@google.com754de5f2014-02-24 19:38:20 +00001759bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001760 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001761}
1762
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001763bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001764 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001765}
1766
msarettfbfa2582016-08-12 08:29:08 -07001767static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1768#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1769 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1770 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1771 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1772 return 0xF != _mm_movemask_ps(mask);
1773#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1774 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1775 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1776 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1777 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1778#else
1779 SkRect devRectAsRect;
1780 SkRect devClipAsRect;
1781 devRect.store(&devRectAsRect.fLeft);
1782 devClip.store(&devClipAsRect.fLeft);
1783 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1784#endif
1785}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001786
msarettfbfa2582016-08-12 08:29:08 -07001787// It's important for this function to not be inlined. Otherwise the compiler will share code
1788// between the fast path and the slow path, resulting in two slow paths.
1789static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1790 const SkMatrix& matrix) {
1791 SkRect deviceRect;
1792 matrix.mapRect(&deviceRect, src);
1793 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1794}
1795
1796bool SkCanvas::quickReject(const SkRect& src) const {
1797#ifdef SK_DEBUG
1798 // Verify that fDeviceClipBounds are set properly.
1799 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001800 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001801 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001802 } else {
msarettfbfa2582016-08-12 08:29:08 -07001803 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001804 }
msarettfbfa2582016-08-12 08:29:08 -07001805
msarett9637ea92016-08-18 14:03:30 -07001806 // Verify that fIsScaleTranslate is set properly.
1807 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001808#endif
1809
msarett9637ea92016-08-18 14:03:30 -07001810 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001811 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1812 }
1813
1814 // We inline the implementation of mapScaleTranslate() for the fast path.
1815 float sx = fMCRec->fMatrix.getScaleX();
1816 float sy = fMCRec->fMatrix.getScaleY();
1817 float tx = fMCRec->fMatrix.getTranslateX();
1818 float ty = fMCRec->fMatrix.getTranslateY();
1819 Sk4f scale(sx, sy, sx, sy);
1820 Sk4f trans(tx, ty, tx, ty);
1821
1822 // Apply matrix.
1823 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1824
1825 // Make sure left < right, top < bottom.
1826 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1827 Sk4f min = Sk4f::Min(ltrb, rblt);
1828 Sk4f max = Sk4f::Max(ltrb, rblt);
1829 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1830 // ARM this sequence generates the fastest (a single instruction).
1831 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1832
1833 // Check if the device rect is NaN or outside the clip.
1834 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001835}
1836
reed@google.com3b3e8952012-08-16 20:53:31 +00001837bool SkCanvas::quickReject(const SkPath& path) const {
1838 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001839}
1840
reed@google.com3b3e8952012-08-16 20:53:31 +00001841bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001842 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001843 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001844 return false;
1845 }
1846
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001847 SkMatrix inverse;
1848 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001849 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001850 if (bounds) {
1851 bounds->setEmpty();
1852 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001853 return false;
1854 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001855
bsalomon49f085d2014-09-05 13:34:00 -07001856 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001857 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001858 // adjust it outwards in case we are antialiasing
1859 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001860
reed@google.com8f4d2302013-12-17 16:44:46 +00001861 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1862 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001863 inverse.mapRect(bounds, r);
1864 }
1865 return true;
1866}
1867
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001868bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001869 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001870 if (clip.isEmpty()) {
1871 if (bounds) {
1872 bounds->setEmpty();
1873 }
1874 return false;
1875 }
1876
bsalomon49f085d2014-09-05 13:34:00 -07001877 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001878 *bounds = clip.getBounds();
1879 }
1880 return true;
1881}
1882
reed@android.com8a1c16f2008-12-17 15:59:43 +00001883const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001884 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001885}
1886
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001887const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001888 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001889}
1890
robertphillips175dd9b2016-04-28 14:32:04 -07001891GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001892 SkBaseDevice* dev = this->getTopDevice();
robertphillips175dd9b2016-04-28 14:32:04 -07001893 return dev ? dev->accessDrawContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001894}
1895
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001896GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001897 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001898 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001899}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001900
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001901void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1902 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001903 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001904 if (outer.isEmpty()) {
1905 return;
1906 }
1907 if (inner.isEmpty()) {
1908 this->drawRRect(outer, paint);
1909 return;
1910 }
1911
1912 // We don't have this method (yet), but technically this is what we should
1913 // be able to assert...
1914 // SkASSERT(outer.contains(inner));
1915 //
1916 // For now at least check for containment of bounds
1917 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1918
1919 this->onDrawDRRect(outer, inner, paint);
1920}
1921
reed41af9662015-01-05 07:49:08 -08001922// These need to stop being virtual -- clients need to override the onDraw... versions
1923
1924void SkCanvas::drawPaint(const SkPaint& paint) {
1925 this->onDrawPaint(paint);
1926}
1927
1928void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1929 this->onDrawRect(r, paint);
1930}
1931
msarettdca352e2016-08-26 06:37:45 -07001932void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1933 if (region.isEmpty()) {
1934 return;
1935 }
1936
1937 if (region.isRect()) {
1938 return this->drawIRect(region.getBounds(), paint);
1939 }
1940
1941 this->onDrawRegion(region, paint);
1942}
1943
reed41af9662015-01-05 07:49:08 -08001944void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1945 this->onDrawOval(r, paint);
1946}
1947
1948void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1949 this->onDrawRRect(rrect, paint);
1950}
1951
1952void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1953 this->onDrawPoints(mode, count, pts, paint);
1954}
1955
1956void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1957 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1958 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1959 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1960 indices, indexCount, paint);
1961}
1962
1963void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1964 this->onDrawPath(path, paint);
1965}
1966
reeda85d4d02015-05-06 12:56:48 -07001967void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001968 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001969 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001970}
1971
reede47829b2015-08-06 10:02:53 -07001972void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1973 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001974 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001975 if (dst.isEmpty() || src.isEmpty()) {
1976 return;
1977 }
1978 this->onDrawImageRect(image, &src, dst, paint, constraint);
1979}
reed41af9662015-01-05 07:49:08 -08001980
reed84984ef2015-07-17 07:09:43 -07001981void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1982 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001983 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001984 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001985}
1986
reede47829b2015-08-06 10:02:53 -07001987void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1988 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001989 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001990 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1991 constraint);
1992}
reede47829b2015-08-06 10:02:53 -07001993
reed4c21dc52015-06-25 12:32:03 -07001994void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1995 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001996 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001997 if (dst.isEmpty()) {
1998 return;
1999 }
msarett552bca92016-08-03 06:53:26 -07002000 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2001 this->onDrawImageNine(image, center, dst, paint);
2002 } else {
reede47829b2015-08-06 10:02:53 -07002003 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002004 }
reed4c21dc52015-06-25 12:32:03 -07002005}
2006
msarett16882062016-08-16 09:31:08 -07002007void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2008 const SkPaint* paint) {
2009 RETURN_ON_NULL(image);
2010 if (dst.isEmpty()) {
2011 return;
2012 }
2013 if (SkLatticeIter::Valid(image->width(), image->height(), lattice)) {
2014 this->onDrawImageLattice(image, lattice, dst, paint);
2015 } else {
2016 this->drawImageRect(image, dst, paint);
2017 }
2018}
2019
reed41af9662015-01-05 07:49:08 -08002020void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002021 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002022 return;
2023 }
reed41af9662015-01-05 07:49:08 -08002024 this->onDrawBitmap(bitmap, dx, dy, paint);
2025}
2026
reede47829b2015-08-06 10:02:53 -07002027void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002028 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002029 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002030 return;
2031 }
reede47829b2015-08-06 10:02:53 -07002032 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002033}
2034
reed84984ef2015-07-17 07:09:43 -07002035void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2036 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002037 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002038}
2039
reede47829b2015-08-06 10:02:53 -07002040void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2041 SrcRectConstraint constraint) {
2042 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2043 constraint);
2044}
reede47829b2015-08-06 10:02:53 -07002045
reed41af9662015-01-05 07:49:08 -08002046void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2047 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002048 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002049 return;
2050 }
msarett552bca92016-08-03 06:53:26 -07002051 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2052 this->onDrawBitmapNine(bitmap, center, dst, paint);
2053 } else {
reeda5517e22015-07-14 10:54:12 -07002054 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002055 }
reed41af9662015-01-05 07:49:08 -08002056}
2057
msarettc573a402016-08-02 08:05:56 -07002058void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2059 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002060 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002061 return;
2062 }
msarett16882062016-08-16 09:31:08 -07002063 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), lattice)) {
2064 this->onDrawBitmapLattice(bitmap, lattice, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002065 } else {
msarett16882062016-08-16 09:31:08 -07002066 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002067 }
msarettc573a402016-08-02 08:05:56 -07002068}
2069
reed71c3c762015-06-24 10:29:17 -07002070void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2071 const SkColor colors[], int count, SkXfermode::Mode mode,
2072 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002073 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002074 if (count <= 0) {
2075 return;
2076 }
2077 SkASSERT(atlas);
2078 SkASSERT(xform);
2079 SkASSERT(tex);
2080 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2081}
2082
reedf70b5312016-03-04 16:36:20 -08002083void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2084 if (key) {
2085 this->onDrawAnnotation(rect, key, value);
2086 }
2087}
2088
reede47829b2015-08-06 10:02:53 -07002089void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2090 const SkPaint* paint, SrcRectConstraint constraint) {
2091 if (src) {
2092 this->drawImageRect(image, *src, dst, paint, constraint);
2093 } else {
2094 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2095 dst, paint, constraint);
2096 }
2097}
2098void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2099 const SkPaint* paint, SrcRectConstraint constraint) {
2100 if (src) {
2101 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2102 } else {
2103 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2104 dst, paint, constraint);
2105 }
2106}
2107
tomhudsoncb3bd182016-05-18 07:24:16 -07002108void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2109 SkIRect layer_bounds = this->getTopLayerBounds();
2110 if (matrix) {
2111 *matrix = this->getTotalMatrix();
2112 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2113 }
2114 if (clip_bounds) {
2115 this->getClipDeviceBounds(clip_bounds);
2116 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2117 }
2118}
2119
reed@android.com8a1c16f2008-12-17 15:59:43 +00002120//////////////////////////////////////////////////////////////////////////////
2121// These are the virtual drawing methods
2122//////////////////////////////////////////////////////////////////////////////
2123
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002124void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002125 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002126 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2127 }
2128}
2129
reed41af9662015-01-05 07:49:08 -08002130void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002131 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002132 this->internalDrawPaint(paint);
2133}
2134
2135void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002136 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002137
2138 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002139 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002140 }
2141
reed@google.com4e2b3d32011-04-07 14:18:59 +00002142 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002143}
2144
reed41af9662015-01-05 07:49:08 -08002145void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2146 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002147 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002148 if ((long)count <= 0) {
2149 return;
2150 }
2151
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002152 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002153 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002154 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002155 // special-case 2 points (common for drawing a single line)
2156 if (2 == count) {
2157 r.set(pts[0], pts[1]);
2158 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002159 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002160 }
senorblanco87e066e2015-10-28 11:23:36 -07002161 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2162 return;
2163 }
2164 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002165 }
reed@google.coma584aed2012-05-16 14:06:02 +00002166
halcanary96fcdcc2015-08-27 07:41:13 -07002167 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002168
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002169 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002170
reed@android.com8a1c16f2008-12-17 15:59:43 +00002171 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002172 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002173 }
reed@google.com4b226022011-01-11 18:32:13 +00002174
reed@google.com4e2b3d32011-04-07 14:18:59 +00002175 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002176}
2177
reed4a167172016-08-18 17:15:25 -07002178static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2179 return ((intptr_t)paint.getImageFilter() |
2180#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2181 (intptr_t)canvas->getDrawFilter() |
2182#endif
2183 (intptr_t)paint.getLooper() ) != 0;
2184}
2185
reed41af9662015-01-05 07:49:08 -08002186void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002187 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002188 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002189 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002190 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002191 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2192 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2193 SkRect tmp(r);
2194 tmp.sort();
2195
senorblanco87e066e2015-10-28 11:23:36 -07002196 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2197 return;
2198 }
2199 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002200 }
reed@google.com4b226022011-01-11 18:32:13 +00002201
reed4a167172016-08-18 17:15:25 -07002202 if (needs_autodrawlooper(this, paint)) {
2203 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002204
reed4a167172016-08-18 17:15:25 -07002205 while (iter.next()) {
2206 iter.fDevice->drawRect(iter, r, looper.paint());
2207 }
2208
2209 LOOPER_END
2210 } else {
2211 this->predrawNotify(bounds, &paint, false);
2212 SkDrawIter iter(this);
2213 while (iter.next()) {
2214 iter.fDevice->drawRect(iter, r, paint);
2215 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002216 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002217}
2218
msarett44df6512016-08-25 13:54:30 -07002219void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2220 SkRect storage;
2221 SkRect regionRect = SkRect::Make(region.getBounds());
2222 const SkRect* bounds = nullptr;
2223 if (paint.canComputeFastBounds()) {
2224 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2225 return;
2226 }
2227 bounds = &regionRect;
2228 }
2229
2230 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2231
2232 while (iter.next()) {
2233 iter.fDevice->drawRegion(iter, region, looper.paint());
2234 }
2235
2236 LOOPER_END
2237}
2238
reed41af9662015-01-05 07:49:08 -08002239void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002240 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002241 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002242 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002243 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002244 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2245 return;
2246 }
2247 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002248 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002249
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002250 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002251
2252 while (iter.next()) {
2253 iter.fDevice->drawOval(iter, oval, looper.paint());
2254 }
2255
2256 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002257}
2258
bsalomonac3aa242016-08-19 11:25:19 -07002259void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2260 SkScalar sweepAngle, bool useCenter,
2261 const SkPaint& paint) {
2262 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2263 const SkRect* bounds = nullptr;
2264 if (paint.canComputeFastBounds()) {
2265 SkRect storage;
2266 // Note we're using the entire oval as the bounds.
2267 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2268 return;
2269 }
2270 bounds = &oval;
2271 }
2272
2273 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2274
2275 while (iter.next()) {
2276 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2277 }
2278
2279 LOOPER_END
2280}
2281
reed41af9662015-01-05 07:49:08 -08002282void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002283 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002284 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002285 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002286 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002287 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2288 return;
2289 }
2290 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002291 }
2292
2293 if (rrect.isRect()) {
2294 // call the non-virtual version
2295 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002296 return;
2297 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002298 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002299 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2300 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002301 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002302
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002303 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002304
2305 while (iter.next()) {
2306 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2307 }
2308
2309 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002310}
2311
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002312void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2313 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002314 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002315 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002316 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002317 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2318 return;
2319 }
2320 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002321 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002322
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002323 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002324
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002325 while (iter.next()) {
2326 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2327 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002328
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002329 LOOPER_END
2330}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002331
reed41af9662015-01-05 07:49:08 -08002332void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002333 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002334 if (!path.isFinite()) {
2335 return;
2336 }
2337
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002338 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002339 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002340 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002341 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002342 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2343 return;
2344 }
2345 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002346 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002347
2348 const SkRect& r = path.getBounds();
2349 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002350 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002351 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002352 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002353 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002354 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002355
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002356 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002357
2358 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002359 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002360 }
2361
reed@google.com4e2b3d32011-04-07 14:18:59 +00002362 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002363}
2364
reed262a71b2015-12-05 13:07:27 -08002365bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002366 if (!paint.getImageFilter()) {
2367 return false;
2368 }
2369
2370 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002371 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002372 return false;
2373 }
2374
2375 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2376 // Once we can filter and the filter will return a result larger than itself, we should be
2377 // able to remove this constraint.
2378 // skbug.com/4526
2379 //
2380 SkPoint pt;
2381 ctm.mapXY(x, y, &pt);
2382 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2383 return ir.contains(fMCRec->fRasterClip.getBounds());
2384}
2385
reeda85d4d02015-05-06 12:56:48 -07002386void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002387 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002388 SkRect bounds = SkRect::MakeXYWH(x, y,
2389 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002390 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002391 SkRect tmp = bounds;
2392 if (paint) {
2393 paint->computeFastBounds(tmp, &tmp);
2394 }
2395 if (this->quickReject(tmp)) {
2396 return;
2397 }
reeda85d4d02015-05-06 12:56:48 -07002398 }
halcanary9d524f22016-03-29 09:03:52 -07002399
reeda85d4d02015-05-06 12:56:48 -07002400 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002401 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002402 paint = lazy.init();
2403 }
reed262a71b2015-12-05 13:07:27 -08002404
reeda2217ef2016-07-20 06:04:34 -07002405 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002406 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2407 *paint);
2408 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002409 special = this->getDevice()->makeSpecial(image);
2410 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002411 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002412 }
2413 }
2414
reed262a71b2015-12-05 13:07:27 -08002415 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2416
reeda85d4d02015-05-06 12:56:48 -07002417 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002418 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002419 if (special) {
2420 SkPoint pt;
2421 iter.fMatrix->mapXY(x, y, &pt);
2422 iter.fDevice->drawSpecial(iter, special.get(),
2423 SkScalarRoundToInt(pt.fX),
2424 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002425 } else {
2426 iter.fDevice->drawImage(iter, image, x, y, pnt);
2427 }
reeda85d4d02015-05-06 12:56:48 -07002428 }
halcanary9d524f22016-03-29 09:03:52 -07002429
reeda85d4d02015-05-06 12:56:48 -07002430 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002431}
2432
reed41af9662015-01-05 07:49:08 -08002433void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002434 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002435 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002436 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002437 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002438 if (paint) {
2439 paint->computeFastBounds(dst, &storage);
2440 }
2441 if (this->quickReject(storage)) {
2442 return;
2443 }
reeda85d4d02015-05-06 12:56:48 -07002444 }
2445 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002446 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002447 paint = lazy.init();
2448 }
halcanary9d524f22016-03-29 09:03:52 -07002449
senorblancoc41e7e12015-12-07 12:51:30 -08002450 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002451 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002452
reeda85d4d02015-05-06 12:56:48 -07002453 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002454 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002455 }
halcanary9d524f22016-03-29 09:03:52 -07002456
reeda85d4d02015-05-06 12:56:48 -07002457 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002458}
2459
reed41af9662015-01-05 07:49:08 -08002460void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002461 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002462 SkDEBUGCODE(bitmap.validate();)
2463
reed33366972015-10-08 09:22:02 -07002464 if (bitmap.drawsNothing()) {
2465 return;
2466 }
2467
2468 SkLazyPaint lazy;
2469 if (nullptr == paint) {
2470 paint = lazy.init();
2471 }
2472
2473 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2474
2475 SkRect storage;
2476 const SkRect* bounds = nullptr;
2477 if (paint->canComputeFastBounds()) {
2478 bitmap.getBounds(&storage);
2479 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002480 SkRect tmp = storage;
2481 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2482 return;
2483 }
2484 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002485 }
reed@google.com4b226022011-01-11 18:32:13 +00002486
reeda2217ef2016-07-20 06:04:34 -07002487 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002488 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2489 *paint);
2490 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002491 special = this->getDevice()->makeSpecial(bitmap);
2492 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002493 drawAsSprite = false;
2494 }
2495 }
2496
reed262a71b2015-12-05 13:07:27 -08002497 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002498
2499 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002500 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002501 if (special) {
reed262a71b2015-12-05 13:07:27 -08002502 SkPoint pt;
2503 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002504 iter.fDevice->drawSpecial(iter, special.get(),
2505 SkScalarRoundToInt(pt.fX),
2506 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002507 } else {
2508 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2509 }
reed33366972015-10-08 09:22:02 -07002510 }
msarettfbfa2582016-08-12 08:29:08 -07002511
reed33366972015-10-08 09:22:02 -07002512 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002513}
2514
reed@google.com9987ec32011-09-07 11:57:52 +00002515// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002516void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002517 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002518 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002519 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002520 return;
2521 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002522
halcanary96fcdcc2015-08-27 07:41:13 -07002523 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002524 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002525 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2526 return;
2527 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002528 }
reed@google.com3d608122011-11-21 15:16:16 +00002529
reed@google.com33535f32012-09-25 15:37:50 +00002530 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002531 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002532 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002533 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002534
senorblancoc41e7e12015-12-07 12:51:30 -08002535 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002536 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002537
reed@google.com33535f32012-09-25 15:37:50 +00002538 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002539 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002540 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002541
reed@google.com33535f32012-09-25 15:37:50 +00002542 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543}
2544
reed41af9662015-01-05 07:49:08 -08002545void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002546 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002547 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002548 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002549 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002550}
2551
reed4c21dc52015-06-25 12:32:03 -07002552void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2553 const SkPaint* paint) {
2554 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002555
halcanary96fcdcc2015-08-27 07:41:13 -07002556 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002557 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002558 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2559 return;
2560 }
reed@google.com3d608122011-11-21 15:16:16 +00002561 }
halcanary9d524f22016-03-29 09:03:52 -07002562
reed4c21dc52015-06-25 12:32:03 -07002563 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002564 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002565 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002566 }
halcanary9d524f22016-03-29 09:03:52 -07002567
senorblancoc41e7e12015-12-07 12:51:30 -08002568 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002569
reed4c21dc52015-06-25 12:32:03 -07002570 while (iter.next()) {
2571 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002572 }
halcanary9d524f22016-03-29 09:03:52 -07002573
reed4c21dc52015-06-25 12:32:03 -07002574 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002575}
2576
reed41af9662015-01-05 07:49:08 -08002577void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2578 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002579 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002580 SkDEBUGCODE(bitmap.validate();)
2581
halcanary96fcdcc2015-08-27 07:41:13 -07002582 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002583 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002584 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2585 return;
2586 }
reed4c21dc52015-06-25 12:32:03 -07002587 }
halcanary9d524f22016-03-29 09:03:52 -07002588
reed4c21dc52015-06-25 12:32:03 -07002589 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002590 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002591 paint = lazy.init();
2592 }
halcanary9d524f22016-03-29 09:03:52 -07002593
senorblancoc41e7e12015-12-07 12:51:30 -08002594 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002595
reed4c21dc52015-06-25 12:32:03 -07002596 while (iter.next()) {
2597 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2598 }
halcanary9d524f22016-03-29 09:03:52 -07002599
reed4c21dc52015-06-25 12:32:03 -07002600 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002601}
2602
msarett16882062016-08-16 09:31:08 -07002603void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2604 const SkPaint* paint) {
2605 if (nullptr == paint || paint->canComputeFastBounds()) {
2606 SkRect storage;
2607 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2608 return;
2609 }
2610 }
2611
2612 SkLazyPaint lazy;
2613 if (nullptr == paint) {
2614 paint = lazy.init();
2615 }
2616
2617 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2618
2619 while (iter.next()) {
2620 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2621 }
2622
2623 LOOPER_END
2624}
2625
2626void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2627 const SkRect& dst, const SkPaint* paint) {
2628 if (nullptr == paint || paint->canComputeFastBounds()) {
2629 SkRect storage;
2630 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2631 return;
2632 }
2633 }
2634
2635 SkLazyPaint lazy;
2636 if (nullptr == paint) {
2637 paint = lazy.init();
2638 }
2639
2640 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2641
2642 while (iter.next()) {
2643 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2644 }
2645
2646 LOOPER_END
2647}
2648
reed@google.comf67e4cf2011-03-15 20:56:58 +00002649class SkDeviceFilteredPaint {
2650public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002651 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002652 uint32_t filteredFlags = device->filterTextFlags(paint);
2653 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002654 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002655 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002656 fPaint = newPaint;
2657 } else {
2658 fPaint = &paint;
2659 }
2660 }
2661
reed@google.comf67e4cf2011-03-15 20:56:58 +00002662 const SkPaint& paint() const { return *fPaint; }
2663
2664private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002665 const SkPaint* fPaint;
2666 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002667};
2668
bungeman@google.com52c748b2011-08-22 21:30:43 +00002669void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2670 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002671 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002672 draw.fDevice->drawRect(draw, r, paint);
2673 } else {
2674 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002675 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002676 draw.fDevice->drawRect(draw, r, p);
2677 }
2678}
2679
2680void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2681 const char text[], size_t byteLength,
2682 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002683 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002684
2685 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002686 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002687 draw.fRC->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002688 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002689 return;
2690 }
2691
2692 SkScalar width = 0;
2693 SkPoint start;
2694
2695 start.set(0, 0); // to avoid warning
2696 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2697 SkPaint::kStrikeThruText_Flag)) {
2698 width = paint.measureText(text, byteLength);
2699
2700 SkScalar offsetX = 0;
2701 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2702 offsetX = SkScalarHalf(width);
2703 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2704 offsetX = width;
2705 }
2706 start.set(x - offsetX, y);
2707 }
2708
2709 if (0 == width) {
2710 return;
2711 }
2712
2713 uint32_t flags = paint.getFlags();
2714
2715 if (flags & (SkPaint::kUnderlineText_Flag |
2716 SkPaint::kStrikeThruText_Flag)) {
2717 SkScalar textSize = paint.getTextSize();
2718 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2719 SkRect r;
2720
2721 r.fLeft = start.fX;
2722 r.fRight = start.fX + width;
2723
2724 if (flags & SkPaint::kUnderlineText_Flag) {
2725 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2726 start.fY);
2727 r.fTop = offset;
2728 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002729 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002730 }
2731 if (flags & SkPaint::kStrikeThruText_Flag) {
2732 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2733 start.fY);
2734 r.fTop = offset;
2735 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002736 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002737 }
2738 }
2739}
2740
reed@google.come0d9ce82014-04-23 04:00:17 +00002741void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2742 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002743 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002744
2745 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002746 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002747 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002748 DrawTextDecorations(iter, dfp.paint(),
2749 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002750 }
2751
reed@google.com4e2b3d32011-04-07 14:18:59 +00002752 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753}
2754
reed@google.come0d9ce82014-04-23 04:00:17 +00002755void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2756 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002757 SkPoint textOffset = SkPoint::Make(0, 0);
2758
halcanary96fcdcc2015-08-27 07:41:13 -07002759 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002760
reed@android.com8a1c16f2008-12-17 15:59:43 +00002761 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002762 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002763 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002764 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002765 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002766
reed@google.com4e2b3d32011-04-07 14:18:59 +00002767 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002768}
2769
reed@google.come0d9ce82014-04-23 04:00:17 +00002770void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2771 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002772
2773 SkPoint textOffset = SkPoint::Make(0, constY);
2774
halcanary96fcdcc2015-08-27 07:41:13 -07002775 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002776
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002778 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002779 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002780 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002782
reed@google.com4e2b3d32011-04-07 14:18:59 +00002783 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784}
2785
reed@google.come0d9ce82014-04-23 04:00:17 +00002786void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2787 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002788 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002789
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790 while (iter.next()) {
2791 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002792 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002793 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002794
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002795 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002796}
2797
reed45561a02016-07-07 12:47:17 -07002798void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2799 const SkRect* cullRect, const SkPaint& paint) {
2800 if (cullRect && this->quickReject(*cullRect)) {
2801 return;
2802 }
2803
2804 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2805
2806 while (iter.next()) {
2807 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2808 }
2809
2810 LOOPER_END
2811}
2812
fmalita00d5c2c2014-08-21 08:53:26 -07002813void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2814 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002815
fmalita85d5eb92015-03-04 11:20:12 -08002816 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002817 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002818 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002819 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002820 SkRect tmp;
2821 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2822 return;
2823 }
2824 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002825 }
2826
fmalita024f9962015-03-03 19:08:17 -08002827 // We cannot filter in the looper as we normally do, because the paint is
2828 // incomplete at this point (text-related attributes are embedded within blob run paints).
2829 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002830 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002831
fmalita85d5eb92015-03-04 11:20:12 -08002832 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002833
fmalitaaa1b9122014-08-28 14:32:24 -07002834 while (iter.next()) {
2835 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002836 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002837 }
2838
fmalitaaa1b9122014-08-28 14:32:24 -07002839 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002840
2841 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002842}
2843
reed@google.come0d9ce82014-04-23 04:00:17 +00002844// These will become non-virtual, so they always call the (virtual) onDraw... method
2845void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2846 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002847 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002848 if (byteLength) {
2849 this->onDrawText(text, byteLength, x, y, paint);
2850 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002851}
2852void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2853 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002854 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002855 if (byteLength) {
2856 this->onDrawPosText(text, byteLength, pos, paint);
2857 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002858}
2859void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2860 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002861 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002862 if (byteLength) {
2863 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2864 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002865}
2866void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2867 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002868 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002869 if (byteLength) {
2870 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2871 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002872}
reed45561a02016-07-07 12:47:17 -07002873void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2874 const SkRect* cullRect, const SkPaint& paint) {
2875 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2876 if (byteLength) {
2877 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2878 }
2879}
fmalita00d5c2c2014-08-21 08:53:26 -07002880void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2881 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002882 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002883 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002884 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002885}
reed@google.come0d9ce82014-04-23 04:00:17 +00002886
reed41af9662015-01-05 07:49:08 -08002887void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2888 const SkPoint verts[], const SkPoint texs[],
2889 const SkColor colors[], SkXfermode* xmode,
2890 const uint16_t indices[], int indexCount,
2891 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002892 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002893 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002894
reed@android.com8a1c16f2008-12-17 15:59:43 +00002895 while (iter.next()) {
2896 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002897 colors, xmode, indices, indexCount,
2898 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002899 }
reed@google.com4b226022011-01-11 18:32:13 +00002900
reed@google.com4e2b3d32011-04-07 14:18:59 +00002901 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002902}
2903
dandovb3c9d1c2014-08-12 08:34:29 -07002904void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2905 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002906 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002907 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002908 return;
2909 }
mtklein6cfa73a2014-08-13 13:33:49 -07002910
msarett9340c262016-09-22 05:20:21 -07002911 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2912}
2913
2914void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2915 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002916 // Since a patch is always within the convex hull of the control points, we discard it when its
2917 // bounding rectangle is completely outside the current clip.
2918 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002919 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002920 if (this->quickReject(bounds)) {
2921 return;
2922 }
mtklein6cfa73a2014-08-13 13:33:49 -07002923
halcanary96fcdcc2015-08-27 07:41:13 -07002924 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002925
dandovecfff212014-08-04 10:02:00 -07002926 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002927 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002928 }
mtklein6cfa73a2014-08-13 13:33:49 -07002929
dandovecfff212014-08-04 10:02:00 -07002930 LOOPER_END
2931}
2932
reeda8db7282015-07-07 10:22:31 -07002933void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002934 RETURN_ON_NULL(dr);
2935 if (x || y) {
2936 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2937 this->onDrawDrawable(dr, &matrix);
2938 } else {
2939 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002940 }
2941}
2942
reeda8db7282015-07-07 10:22:31 -07002943void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002944 RETURN_ON_NULL(dr);
2945 if (matrix && matrix->isIdentity()) {
2946 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002947 }
reede3b38ce2016-01-08 09:18:44 -08002948 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002949}
2950
2951void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2952 SkRect bounds = dr->getBounds();
2953 if (matrix) {
2954 matrix->mapRect(&bounds);
2955 }
2956 if (this->quickReject(bounds)) {
2957 return;
2958 }
2959 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002960}
2961
reed71c3c762015-06-24 10:29:17 -07002962void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2963 const SkColor colors[], int count, SkXfermode::Mode mode,
2964 const SkRect* cull, const SkPaint* paint) {
2965 if (cull && this->quickReject(*cull)) {
2966 return;
2967 }
2968
2969 SkPaint pnt;
2970 if (paint) {
2971 pnt = *paint;
2972 }
halcanary9d524f22016-03-29 09:03:52 -07002973
halcanary96fcdcc2015-08-27 07:41:13 -07002974 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002975 while (iter.next()) {
2976 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2977 }
2978 LOOPER_END
2979}
2980
reedf70b5312016-03-04 16:36:20 -08002981void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2982 SkASSERT(key);
2983
2984 SkPaint paint;
2985 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2986 while (iter.next()) {
2987 iter.fDevice->drawAnnotation(iter, rect, key, value);
2988 }
2989 LOOPER_END
2990}
2991
reed@android.com8a1c16f2008-12-17 15:59:43 +00002992//////////////////////////////////////////////////////////////////////////////
2993// These methods are NOT virtual, and therefore must call back into virtual
2994// methods, rather than actually drawing themselves.
2995//////////////////////////////////////////////////////////////////////////////
2996
2997void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002998 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002999 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003000 SkPaint paint;
3001
3002 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00003003 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003004 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003005 }
3006 this->drawPaint(paint);
3007}
3008
reed@android.com845fdac2009-06-23 03:01:32 +00003009void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003010 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003011 SkPaint paint;
3012
3013 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00003014 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003015 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003016 }
3017 this->drawPaint(paint);
3018}
3019
3020void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003021 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003022 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00003023
reed@android.com8a1c16f2008-12-17 15:59:43 +00003024 pt.set(x, y);
3025 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3026}
3027
3028void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003029 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003030 SkPoint pt;
3031 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003032
reed@android.com8a1c16f2008-12-17 15:59:43 +00003033 pt.set(x, y);
3034 paint.setColor(color);
3035 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3036}
3037
3038void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3039 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003040 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003041 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003042
reed@android.com8a1c16f2008-12-17 15:59:43 +00003043 pts[0].set(x0, y0);
3044 pts[1].set(x1, y1);
3045 this->drawPoints(kLines_PointMode, 2, pts, paint);
3046}
3047
3048void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3049 SkScalar right, SkScalar bottom,
3050 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003051 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003052 SkRect r;
3053
3054 r.set(left, top, right, bottom);
3055 this->drawRect(r, paint);
3056}
3057
3058void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3059 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003060 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003061 if (radius < 0) {
3062 radius = 0;
3063 }
3064
3065 SkRect r;
3066 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003067 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003068}
3069
3070void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3071 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003072 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003073 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003074 SkRRect rrect;
3075 rrect.setRectXY(r, rx, ry);
3076 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003077 } else {
3078 this->drawRect(r, paint);
3079 }
3080}
3081
reed@android.com8a1c16f2008-12-17 15:59:43 +00003082void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3083 SkScalar sweepAngle, bool useCenter,
3084 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003085 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003086 if (oval.isEmpty() || !sweepAngle) {
3087 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003088 }
bsalomon21af9ca2016-08-25 12:29:23 -07003089 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003090}
3091
3092void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3093 const SkPath& path, SkScalar hOffset,
3094 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003095 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003096 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003097
reed@android.com8a1c16f2008-12-17 15:59:43 +00003098 matrix.setTranslate(hOffset, vOffset);
3099 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3100}
3101
reed@android.comf76bacf2009-05-13 14:00:33 +00003102///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003103
3104/**
3105 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3106 * against the playback cost of recursing into the subpicture to get at its actual ops.
3107 *
3108 * For now we pick a conservatively small value, though measurement (and other heuristics like
3109 * the type of ops contained) may justify changing this value.
3110 */
3111#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003112
reedd5fa1a42014-08-09 11:08:05 -07003113void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003114 RETURN_ON_NULL(picture);
3115
reed1c2c4412015-04-30 13:09:24 -07003116 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003117 if (matrix && matrix->isIdentity()) {
3118 matrix = nullptr;
3119 }
3120 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3121 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3122 picture->playback(this);
3123 } else {
3124 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003125 }
3126}
robertphillips9b14f262014-06-04 05:40:44 -07003127
reedd5fa1a42014-08-09 11:08:05 -07003128void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3129 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003130 if (!paint || paint->canComputeFastBounds()) {
3131 SkRect bounds = picture->cullRect();
3132 if (paint) {
3133 paint->computeFastBounds(bounds, &bounds);
3134 }
3135 if (matrix) {
3136 matrix->mapRect(&bounds);
3137 }
3138 if (this->quickReject(bounds)) {
3139 return;
3140 }
3141 }
3142
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003143 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003144 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003145}
3146
vjiaoblack95302da2016-07-21 10:25:54 -07003147#ifdef SK_EXPERIMENTAL_SHADOWING
3148void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3149 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003150 const SkPaint* paint,
3151 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003152 RETURN_ON_NULL(picture);
3153
3154 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3155
vjiaoblacke6f5d562016-08-25 06:30:23 -07003156 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003157}
3158
3159void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3160 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003161 const SkPaint* paint,
3162 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003163 if (!paint || paint->canComputeFastBounds()) {
3164 SkRect bounds = picture->cullRect();
3165 if (paint) {
3166 paint->computeFastBounds(bounds, &bounds);
3167 }
3168 if (matrix) {
3169 matrix->mapRect(&bounds);
3170 }
3171 if (this->quickReject(bounds)) {
3172 return;
3173 }
3174 }
3175
3176 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3177
vjiaoblacke6f5d562016-08-25 06:30:23 -07003178 sk_sp<SkImage> povDepthMap;
3179 sk_sp<SkImage> diffuseMap;
3180
vjiaoblack904527d2016-08-09 09:32:09 -07003181 // povDepthMap
3182 {
3183 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003184 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3185 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003186 sk_sp<SkLights> povLight = builder.finish();
3187
3188 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3189 picture->cullRect().height(),
3190 kBGRA_8888_SkColorType,
3191 kOpaque_SkAlphaType);
3192
3193 // Create a new surface (that matches the backend of canvas)
3194 // to create the povDepthMap
3195 sk_sp<SkSurface> surf(this->makeSurface(info));
3196
3197 // Wrap another SPFCanvas around the surface
3198 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3199 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3200
3201 // set the depth map canvas to have the light as the user's POV
3202 depthMapCanvas->setLights(std::move(povLight));
3203
3204 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003205 povDepthMap = surf->makeImageSnapshot();
3206 }
3207
3208 // diffuseMap
3209 {
3210 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3211 picture->cullRect().height(),
3212 kBGRA_8888_SkColorType,
3213 kOpaque_SkAlphaType);
3214
3215 sk_sp<SkSurface> surf(this->makeSurface(info));
3216 surf->getCanvas()->drawPicture(picture);
3217
3218 diffuseMap = surf->makeImageSnapshot();
3219 }
vjiaoblack904527d2016-08-09 09:32:09 -07003220
3221 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3222 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003223 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3224 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003225
3226 // TODO: pass the depth to the shader in vertices, or uniforms
3227 // so we don't have to render depth and color separately
3228 for (int i = 0; i < fLights->numLights(); ++i) {
3229 // skip over ambient lights; they don't cast shadows
3230 // lights that have shadow maps do not need updating (because lights are immutable)
3231 sk_sp<SkImage> depthMap;
3232 SkISize shMapSize;
3233
3234 if (fLights->light(i).getShadowMap() != nullptr) {
3235 continue;
3236 }
3237
3238 if (fLights->light(i).isRadial()) {
3239 shMapSize.fHeight = 1;
3240 shMapSize.fWidth = (int) picture->cullRect().width();
3241
3242 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3243 kBGRA_8888_SkColorType,
3244 kOpaque_SkAlphaType);
3245
3246 // Create new surface (that matches the backend of canvas)
3247 // for each shadow map
3248 sk_sp<SkSurface> surf(this->makeSurface(info));
3249
3250 // Wrap another SPFCanvas around the surface
3251 SkCanvas* depthMapCanvas = surf->getCanvas();
3252
3253 SkLights::Builder builder;
3254 builder.add(fLights->light(i));
3255 sk_sp<SkLights> curLight = builder.finish();
3256
3257 sk_sp<SkShader> shadowMapShader;
3258 shadowMapShader = SkRadialShadowMapShader::Make(
3259 povDepthShader, curLight,
3260 (int) picture->cullRect().width(),
3261 (int) picture->cullRect().height());
3262
3263 SkPaint shadowMapPaint;
3264 shadowMapPaint.setShader(std::move(shadowMapShader));
3265
3266 depthMapCanvas->setLights(curLight);
3267
3268 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3269 diffuseMap->height()),
3270 shadowMapPaint);
3271
3272 depthMap = surf->makeImageSnapshot();
3273
3274 } else {
3275 // TODO: compute the correct size of the depth map from the light properties
3276 // TODO: maybe add a kDepth_8_SkColorType
3277 // TODO: find actual max depth of picture
3278 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3279 fLights->light(i), 255,
3280 (int) picture->cullRect().width(),
3281 (int) picture->cullRect().height());
3282
3283 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3284 kBGRA_8888_SkColorType,
3285 kOpaque_SkAlphaType);
3286
3287 // Create a new surface (that matches the backend of canvas)
3288 // for each shadow map
3289 sk_sp<SkSurface> surf(this->makeSurface(info));
3290
3291 // Wrap another SPFCanvas around the surface
3292 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3293 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3294 depthMapCanvas->setShadowParams(params);
3295
3296 // set the depth map canvas to have the light we're drawing.
3297 SkLights::Builder builder;
3298 builder.add(fLights->light(i));
3299 sk_sp<SkLights> curLight = builder.finish();
3300 depthMapCanvas->setLights(std::move(curLight));
3301
3302 depthMapCanvas->drawPicture(picture);
3303 depthMap = surf->makeImageSnapshot();
3304 }
3305
3306 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3307 fLights->light(i).setShadowMap(std::move(depthMap));
3308 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3309 // we blur the variance map
3310 SkPaint blurPaint;
3311 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3312 params.fShadowRadius, nullptr));
3313
3314 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3315 kBGRA_8888_SkColorType,
3316 kOpaque_SkAlphaType);
3317
3318 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3319
3320 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3321
3322 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3323 }
3324 }
3325
3326 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003327 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3328 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003329 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003330 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003331 diffuseMap->height(),
3332 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003333
3334 shadowPaint.setShader(shadowShader);
3335
3336 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003337}
3338#endif
3339
reed@android.com8a1c16f2008-12-17 15:59:43 +00003340///////////////////////////////////////////////////////////////////////////////
3341///////////////////////////////////////////////////////////////////////////////
3342
reed3aafe112016-08-18 12:45:34 -07003343SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003344 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003345
3346 SkASSERT(canvas);
3347
reed3aafe112016-08-18 12:45:34 -07003348 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003349 fDone = !fImpl->next();
3350}
3351
3352SkCanvas::LayerIter::~LayerIter() {
3353 fImpl->~SkDrawIter();
3354}
3355
3356void SkCanvas::LayerIter::next() {
3357 fDone = !fImpl->next();
3358}
3359
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003360SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003361 return fImpl->getDevice();
3362}
3363
3364const SkMatrix& SkCanvas::LayerIter::matrix() const {
3365 return fImpl->getMatrix();
3366}
3367
3368const SkPaint& SkCanvas::LayerIter::paint() const {
3369 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003370 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003371 paint = &fDefaultPaint;
3372 }
3373 return *paint;
3374}
3375
reed1e7f5e72016-04-27 07:49:17 -07003376const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003377int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3378int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003379
3380///////////////////////////////////////////////////////////////////////////////
3381
fmalitac3b589a2014-06-05 12:40:07 -07003382SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003383
3384///////////////////////////////////////////////////////////////////////////////
3385
3386static bool supported_for_raster_canvas(const SkImageInfo& info) {
3387 switch (info.alphaType()) {
3388 case kPremul_SkAlphaType:
3389 case kOpaque_SkAlphaType:
3390 break;
3391 default:
3392 return false;
3393 }
3394
3395 switch (info.colorType()) {
3396 case kAlpha_8_SkColorType:
3397 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003398 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003399 break;
3400 default:
3401 return false;
3402 }
3403
3404 return true;
3405}
3406
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003407SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3408 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003409 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003410 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003411
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003412 SkBitmap bitmap;
3413 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003414 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003415 }
halcanary385fe4d2015-08-26 13:07:48 -07003416 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003417}
reedd5fa1a42014-08-09 11:08:05 -07003418
3419///////////////////////////////////////////////////////////////////////////////
3420
3421SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003422 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003423 : fCanvas(canvas)
3424 , fSaveCount(canvas->getSaveCount())
3425{
bsalomon49f085d2014-09-05 13:34:00 -07003426 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003427 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003428 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003429 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003430 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003431 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003432 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003433 canvas->save();
3434 }
mtklein6cfa73a2014-08-13 13:33:49 -07003435
bsalomon49f085d2014-09-05 13:34:00 -07003436 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003437 canvas->concat(*matrix);
3438 }
3439}
3440
3441SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3442 fCanvas->restoreToCount(fSaveCount);
3443}
reede8f30622016-03-23 18:59:25 -07003444
3445#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3446SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
3447 return this->makeSurface(info, props).release();
3448}
3449#endif
reed73603f32016-09-20 08:42:38 -07003450
3451/////////////////////////////////
3452
3453const SkCanvas::ClipOp SkCanvas::kDifference_Op;
3454const SkCanvas::ClipOp SkCanvas::kIntersect_Op;
3455const SkCanvas::ClipOp SkCanvas::kUnion_Op;
3456const SkCanvas::ClipOp SkCanvas::kXOR_Op;
3457const SkCanvas::ClipOp SkCanvas::kReverseDifference_Op;
3458const SkCanvas::ClipOp SkCanvas::kReplace_Op;
3459
3460static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3461static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3462static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3463static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3464static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3465static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");