blob: e53a104c47fa28406f1d440dbcd670365d877a24 [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
reed2d1afab2016-06-29 14:33:11 -070053//#define SK_SUPPORT_PRECHECK_CLIPRECT
54
reedc83a2972015-07-16 07:40:45 -070055/*
56 * Return true if the drawing this rect would hit every pixels in the canvas.
57 *
58 * Returns false if
59 * - rect does not contain the canvas' bounds
60 * - paint is not fill
61 * - paint would blur or otherwise change the coverage of the rect
62 */
63bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
64 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070065 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
66 (int)kNone_ShaderOverrideOpacity,
67 "need_matching_enums0");
68 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
69 (int)kOpaque_ShaderOverrideOpacity,
70 "need_matching_enums1");
71 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
72 (int)kNotOpaque_ShaderOverrideOpacity,
73 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070074
75 const SkISize size = this->getBaseLayerSize();
76 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
77 if (!this->getClipStack()->quickContains(bounds)) {
78 return false;
79 }
80
81 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070082 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070083 return false; // conservative
84 }
halcanaryc5769b22016-08-10 07:13:21 -070085
86 SkRect devRect;
87 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
88 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070089 return false;
90 }
91 }
92
93 if (paint) {
94 SkPaint::Style paintStyle = paint->getStyle();
95 if (!(paintStyle == SkPaint::kFill_Style ||
96 paintStyle == SkPaint::kStrokeAndFill_Style)) {
97 return false;
98 }
99 if (paint->getMaskFilter() || paint->getLooper()
100 || paint->getPathEffect() || paint->getImageFilter()) {
101 return false; // conservative
102 }
103 }
104 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
105}
106
107///////////////////////////////////////////////////////////////////////////////////////////////////
108
reedd990e2f2014-12-22 11:58:30 -0800109static bool gIgnoreSaveLayerBounds;
110void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
111 gIgnoreSaveLayerBounds = ignore;
112}
113bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
114 return gIgnoreSaveLayerBounds;
115}
116
reed0acf1b42014-12-22 16:12:38 -0800117static bool gTreatSpriteAsBitmap;
118void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
119 gTreatSpriteAsBitmap = spriteAsBitmap;
120}
121bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
122 return gTreatSpriteAsBitmap;
123}
124
reed@google.comda17f752012-08-16 18:27:05 +0000125// experimental for faster tiled drawing...
126//#define SK_ENABLE_CLIP_QUICKREJECT
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127//#define SK_TRACE_SAVERESTORE
128
129#ifdef SK_TRACE_SAVERESTORE
130 static int gLayerCounter;
131 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
132 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
133
134 static int gRecCounter;
135 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
136 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
137
138 static int gCanvasCounter;
139 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
140 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
141#else
142 #define inc_layer()
143 #define dec_layer()
144 #define inc_rec()
145 #define dec_rec()
146 #define inc_canvas()
147 #define dec_canvas()
148#endif
149
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000150typedef SkTLazy<SkPaint> SkLazyPaint;
151
reedc83a2972015-07-16 07:40:45 -0700152void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000153 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700154 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
155 ? SkSurface::kDiscard_ContentChangeMode
156 : SkSurface::kRetain_ContentChangeMode);
157 }
158}
159
160void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
161 ShaderOverrideOpacity overrideOpacity) {
162 if (fSurfaceBase) {
163 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
164 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
165 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
166 // and therefore we don't care which mode we're in.
167 //
168 if (fSurfaceBase->outstandingImageSnapshot()) {
169 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
170 mode = SkSurface::kDiscard_ContentChangeMode;
171 }
172 }
173 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000174 }
175}
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000179/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 The clip/matrix/proc are fields that reflect the top of the save/restore
181 stack. Whenever the canvas changes, it marks a dirty flag, and then before
182 these are used (assuming we're not on a layer) we rebuild these cache
183 values: they reflect the top of the save stack, but translated and clipped
184 by the device's XY offset and bitmap-bounds.
185*/
186struct DeviceCM {
187 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000188 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000189 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000190 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700191 const SkMatrix* fMatrix;
192 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700193 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194
reed96e657d2015-03-10 17:30:07 -0700195 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700196 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700197 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700198 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700200 {
reed2c9e2002016-07-25 08:05:22 -0700201 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000202 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700203 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000206 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700207 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700208 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000209 }
reed@google.com4b226022011-01-11 18:32:13 +0000210
mtkleinfeaadee2015-04-08 11:25:48 -0700211 void reset(const SkIRect& bounds) {
212 SkASSERT(!fPaint);
213 SkASSERT(!fNext);
214 SkASSERT(fDevice);
215 fClip.setRect(bounds);
216 }
217
reed@google.com045e62d2011-10-24 12:19:46 +0000218 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700219 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000220 int x = fDevice->getOrigin().x();
221 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 int width = fDevice->width();
223 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000224
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 if ((x | y) == 0) {
226 fMatrix = &totalMatrix;
227 fClip = totalClip;
228 } else {
229 fMatrixStorage = totalMatrix;
230 fMatrixStorage.postTranslate(SkIntToScalar(-x),
231 SkIntToScalar(-y));
232 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 totalClip.translate(-x, -y, &fClip);
235 }
236
reed@google.com045e62d2011-10-24 12:19:46 +0000237 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238
239 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000242 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 SkRegion::kDifference_Op);
244 }
reed@google.com4b226022011-01-11 18:32:13 +0000245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246#ifdef SK_DEBUG
247 if (!fClip.isEmpty()) {
248 SkIRect deviceR;
249 deviceR.set(0, 0, width, height);
250 SkASSERT(deviceR.contains(fClip.getBounds()));
251 }
252#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000253 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254};
255
256/* This is the record we keep for each save/restore level in the stack.
257 Since a level optionally copies the matrix and/or stack, we have pointers
258 for these fields. If the value is copied for this level, the copy is
259 stored in the ...Storage field, and the pointer points to that. If the
260 value is not copied for this level, we ignore ...Storage, and just point
261 at the corresponding value in the previous level in the stack.
262*/
263class SkCanvas::MCRec {
264public:
reed1f836ee2014-07-07 07:49:34 -0700265 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700266 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 /* If there are any layers in the stack, this points to the top-most
268 one that is at or below this level in the stack (so we know what
269 bitmap/device to draw into from this level. This value is NOT
270 reference counted, since the real owner is either our fLayer field,
271 or a previous one in a lower level.)
272 */
reed2ff1fce2014-12-11 07:07:37 -0800273 DeviceCM* fTopLayer;
274 SkRasterClip fRasterClip;
275 SkMatrix fMatrix;
276 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277
vjiaoblacke5de1302016-07-13 14:05:28 -0700278 // This is the current cumulative depth (aggregate of all done translateZ calls)
279 SkScalar fCurDrawDepth;
280
reedd9544982014-09-09 18:46:22 -0700281 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700282 fFilter = nullptr;
283 fLayer = nullptr;
284 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800285 fMatrix.reset();
286 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700287 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700288
reedd9544982014-09-09 18:46:22 -0700289 // don't bother initializing fNext
290 inc_rec();
291 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700292 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
293 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700294 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700295 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700296 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800297 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700298
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299 // don't bother initializing fNext
300 inc_rec();
301 }
302 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000303 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700304 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305 dec_rec();
306 }
mtkleinfeaadee2015-04-08 11:25:48 -0700307
308 void reset(const SkIRect& bounds) {
309 SkASSERT(fLayer);
310 SkASSERT(fDeferredSaveCount == 0);
311
312 fMatrix.reset();
313 fRasterClip.setRect(bounds);
314 fLayer->reset(bounds);
315 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316};
317
reed02f9ed72016-09-06 09:06:18 -0700318static SkIRect compute_device_bounds(SkBaseDevice* device) {
319 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
320 device->width(), device->height());
321}
322
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323class SkDrawIter : public SkDraw {
324public:
reed3aafe112016-08-18 12:45:34 -0700325 SkDrawIter(SkCanvas* canvas) {
junov@google.com4370aed2012-01-18 16:21:08 +0000326 canvas = canvas->canvasForDrawIter();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 canvas->updateDeviceCMCache();
328
reed687fa1c2015-04-07 08:00:56 -0700329 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700331
332 fMultiDeviceCS = nullptr;
333 if (fCurrLayer->fNext) {
334 fMultiDeviceCS = canvas->fClipStack;
335 fMultiDeviceCS->save();
336 }
337 }
338
339 ~SkDrawIter() {
340 if (fMultiDeviceCS) {
341 fMultiDeviceCS->restore();
342 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 }
reed@google.com4b226022011-01-11 18:32:13 +0000344
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700346 if (fMultiDeviceCS && fDevice) {
347 // remove the previous device's bounds
348 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice),
349 SkRegion::kDifference_Op);
350 }
351
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700353 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
354 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 }
356
reed@google.comf68c5e22012-02-24 16:38:58 +0000357 const DeviceCM* rec = fCurrLayer;
358 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359
360 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000361 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700363 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700364 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700365 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000367 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368
369 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700370 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000371
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372 return true;
373 }
374 return false;
375 }
reed@google.com4b226022011-01-11 18:32:13 +0000376
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000377 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700378 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000379 int getX() const { return fDevice->getOrigin().x(); }
380 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000383
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385 const DeviceCM* fCurrLayer;
386 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700387 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388
389 typedef SkDraw INHERITED;
390};
391
392/////////////////////////////////////////////////////////////////////////////
393
reeddbc3cef2015-04-29 12:18:57 -0700394static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
395 return lazy->isValid() ? lazy->get() : lazy->set(orig);
396}
397
398/**
399 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700400 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700401 */
reedd053ce92016-03-22 10:17:23 -0700402static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700403 SkImageFilter* imgf = paint.getImageFilter();
404 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700405 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700406 }
407
reedd053ce92016-03-22 10:17:23 -0700408 SkColorFilter* imgCFPtr;
409 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700410 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700411 }
reedd053ce92016-03-22 10:17:23 -0700412 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700413
414 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700415 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700416 // there is no existing paint colorfilter, so we can just return the imagefilter's
417 return imgCF;
418 }
419
420 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
421 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700422 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700423}
424
senorblanco87e066e2015-10-28 11:23:36 -0700425/**
426 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
427 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
428 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
429 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
430 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
431 * conservative "effective" bounds based on the settings in the paint... with one exception. This
432 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
433 * deliberately ignored.
434 */
435static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
436 const SkRect& rawBounds,
437 SkRect* storage) {
438 SkPaint tmpUnfiltered(paint);
439 tmpUnfiltered.setImageFilter(nullptr);
440 if (tmpUnfiltered.canComputeFastBounds()) {
441 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
442 } else {
443 return rawBounds;
444 }
445}
446
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447class AutoDrawLooper {
448public:
senorblanco87e066e2015-10-28 11:23:36 -0700449 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
450 // paint. It's used to determine the size of the offscreen layer for filters.
451 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700452 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700453 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000454 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800455#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800457#else
458 fFilter = nullptr;
459#endif
reed4a8126e2014-09-22 07:29:03 -0700460 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000461 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700462 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000463 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464
reedd053ce92016-03-22 10:17:23 -0700465 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700466 if (simplifiedCF) {
467 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700468 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700469 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700470 fPaint = paint;
471 }
472
473 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700474 /**
475 * We implement ImageFilters for a given draw by creating a layer, then applying the
476 * imagefilter to the pixels of that layer (its backing surface/image), and then
477 * we call restore() to xfer that layer to the main canvas.
478 *
479 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
480 * 2. Generate the src pixels:
481 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
482 * return (fPaint). We then draw the primitive (using srcover) into a cleared
483 * buffer/surface.
484 * 3. Restore the layer created in #1
485 * The imagefilter is passed the buffer/surface from the layer (now filled with the
486 * src pixels of the primitive). It returns a new "filtered" buffer, which we
487 * draw onto the previous layer using the xfermode from the original paint.
488 */
reed@google.com8926b162012-03-23 15:36:36 +0000489 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700490 tmp.setImageFilter(fPaint->getImageFilter());
reedcfb6bdf2016-03-29 11:32:50 -0700491 tmp.setXfermode(sk_ref_sp(fPaint->getXfermode()));
senorblanco87e066e2015-10-28 11:23:36 -0700492 SkRect storage;
493 if (rawBounds) {
494 // Make rawBounds include all paint outsets except for those due to image filters.
495 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
496 }
reedbfd5f172016-01-07 11:28:08 -0800497 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700498 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700499 fTempLayerForImageFilter = true;
500 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000501 }
502
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000503 if (SkDrawLooper* looper = paint.getLooper()) {
504 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
505 looper->contextSize());
506 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000507 fIsSimple = false;
508 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700509 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000510 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700511 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000512 }
513 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000514
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700516 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000517 fCanvas->internalRestore();
518 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000519 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000521
reed@google.com4e2b3d32011-04-07 14:18:59 +0000522 const SkPaint& paint() const {
523 SkASSERT(fPaint);
524 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000526
reed@google.com129ec222012-05-15 13:24:09 +0000527 bool next(SkDrawFilter::Type drawType) {
528 if (fDone) {
529 return false;
530 } else if (fIsSimple) {
531 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000532 return !fPaint->nothingToDraw();
533 } else {
534 return this->doNext(drawType);
535 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000536 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000537
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538private:
reeddbc3cef2015-04-29 12:18:57 -0700539 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
540 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000541 SkCanvas* fCanvas;
542 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000543 SkDrawFilter* fFilter;
544 const SkPaint* fPaint;
545 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700546 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000547 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000548 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000549 SkDrawLooper::Context* fLooperContext;
550 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000551
552 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553};
554
reed@google.com129ec222012-05-15 13:24:09 +0000555bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700556 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000557 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700558 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000559
reeddbc3cef2015-04-29 12:18:57 -0700560 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
561 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000562
reed5c476fb2015-04-20 08:04:21 -0700563 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700564 paint->setImageFilter(nullptr);
565 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000566 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000567
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000568 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000569 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000570 return false;
571 }
572 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000573 if (!fFilter->filter(paint, drawType)) {
574 fDone = true;
575 return false;
576 }
halcanary96fcdcc2015-08-27 07:41:13 -0700577 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000578 // no looper means we only draw once
579 fDone = true;
580 }
581 }
582 fPaint = paint;
583
584 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000585 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000586 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000587 }
588
589 // call this after any possible paint modifiers
590 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700591 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000592 return false;
593 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000594 return true;
595}
596
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597////////// macros to place around the internal draw calls //////////////////
598
reed3aafe112016-08-18 12:45:34 -0700599#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
600 this->predrawNotify(); \
601 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
602 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800603 SkDrawIter iter(this);
604
605
reed@google.com8926b162012-03-23 15:36:36 +0000606#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000607 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700608 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000609 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000610 SkDrawIter iter(this);
611
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000612#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000613 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700614 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000615 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000616 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000617
reedc83a2972015-07-16 07:40:45 -0700618#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
619 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700620 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700621 while (looper.next(type)) { \
622 SkDrawIter iter(this);
623
reed@google.com4e2b3d32011-04-07 14:18:59 +0000624#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625
626////////////////////////////////////////////////////////////////////////////
627
msarettfbfa2582016-08-12 08:29:08 -0700628static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
629 if (bounds.isEmpty()) {
630 return SkRect::MakeEmpty();
631 }
632
633 // Expand bounds out by 1 in case we are anti-aliasing. We store the
634 // bounds as floats to enable a faster quick reject implementation.
635 SkRect dst;
636 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
637 return dst;
638}
639
mtkleinfeaadee2015-04-08 11:25:48 -0700640void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
641 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700642 fClipStack->reset();
643 fMCRec->reset(bounds);
644
645 // We're peering through a lot of structs here. Only at this scope do we
646 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
647 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700648 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700649 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700650}
651
reedd9544982014-09-09 18:46:22 -0700652SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800653 if (device && device->forceConservativeRasterClip()) {
654 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
655 }
656 // Since init() is only called once by our constructors, it is safe to perform this
657 // const-cast.
658 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
659
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000660 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000661 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700662 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800663 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700664 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700665#ifdef SK_EXPERIMENTAL_SHADOWING
666 fLights = nullptr;
667#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668
halcanary385fe4d2015-08-26 13:07:48 -0700669 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700670
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700672 new (fMCRec) MCRec(fConservativeRasterClip);
msarett9637ea92016-08-18 14:03:30 -0700673 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674
reeda499f902015-05-01 09:34:31 -0700675 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
676 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700677 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700678 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700679
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681
halcanary96fcdcc2015-08-27 07:41:13 -0700682 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000683
reedf92c8662014-08-18 08:02:43 -0700684 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700685 // The root device and the canvas should always have the same pixel geometry
686 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700687 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800688 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700689 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700690 }
msarettfbfa2582016-08-12 08:29:08 -0700691
reedf92c8662014-08-18 08:02:43 -0700692 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693}
694
reed@google.comcde92112011-07-06 20:00:52 +0000695SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000696 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700697 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800698 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000699{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000700 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000701
halcanary96fcdcc2015-08-27 07:41:13 -0700702 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000703}
704
reedd9544982014-09-09 18:46:22 -0700705static SkBitmap make_nopixels(int width, int height) {
706 SkBitmap bitmap;
707 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
708 return bitmap;
709}
710
711class SkNoPixelsBitmapDevice : public SkBitmapDevice {
712public:
robertphillipsfcf78292015-06-19 11:49:52 -0700713 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
714 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800715 {
716 this->setOrigin(bounds.x(), bounds.y());
717 }
reedd9544982014-09-09 18:46:22 -0700718
719private:
piotaixrb5fae932014-09-24 13:03:30 -0700720
reedd9544982014-09-09 18:46:22 -0700721 typedef SkBitmapDevice INHERITED;
722};
723
reed96a857e2015-01-25 10:33:58 -0800724SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000725 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800726 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800727 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000728{
729 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700730
halcanary385fe4d2015-08-26 13:07:48 -0700731 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
732 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700733}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000734
reed78e27682014-11-19 08:04:34 -0800735SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700736 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700737 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800738 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700739{
740 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700741
halcanary385fe4d2015-08-26 13:07:48 -0700742 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700743}
744
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000745SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000746 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700747 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800748 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000749{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700751
reedd9544982014-09-09 18:46:22 -0700752 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753}
754
robertphillipsfcf78292015-06-19 11:49:52 -0700755SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
756 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700757 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800758 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700759{
760 inc_canvas();
761
762 this->init(device, flags);
763}
764
reed4a8126e2014-09-22 07:29:03 -0700765SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700766 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700767 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800768 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700769{
770 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700771
halcanary385fe4d2015-08-26 13:07:48 -0700772 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700773 this->init(device, kDefault_InitFlags);
774}
reed29c857d2014-09-21 10:25:07 -0700775
reed4a8126e2014-09-22 07:29:03 -0700776SkCanvas::SkCanvas(const SkBitmap& bitmap)
777 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
778 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800779 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700780{
781 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700782
halcanary385fe4d2015-08-26 13:07:48 -0700783 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700784 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000785}
786
787SkCanvas::~SkCanvas() {
788 // free up the contents of our deque
789 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000790
reed@android.com8a1c16f2008-12-17 15:59:43 +0000791 this->internalRestore(); // restore the last, since we're going away
792
halcanary385fe4d2015-08-26 13:07:48 -0700793 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000794
reed@android.com8a1c16f2008-12-17 15:59:43 +0000795 dec_canvas();
796}
797
fmalita53d9f1c2016-01-25 06:23:54 -0800798#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000799SkDrawFilter* SkCanvas::getDrawFilter() const {
800 return fMCRec->fFilter;
801}
802
803SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700804 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
806 return filter;
807}
fmalita77650002016-01-21 18:47:11 -0800808#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000810SkMetaData& SkCanvas::getMetaData() {
811 // metadata users are rare, so we lazily allocate it. If that changes we
812 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700813 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000814 fMetaData = new SkMetaData;
815 }
816 return *fMetaData;
817}
818
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819///////////////////////////////////////////////////////////////////////////////
820
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000821void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700822 this->onFlush();
823}
824
825void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000826 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000827 if (device) {
828 device->flush();
829 }
830}
831
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000832SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000833 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000834 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
835}
836
senorblancoafc7cce2016-02-02 18:44:15 -0800837SkIRect SkCanvas::getTopLayerBounds() const {
838 SkBaseDevice* d = this->getTopDevice();
839 if (!d) {
840 return SkIRect::MakeEmpty();
841 }
842 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
843}
844
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000845SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000846 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000847 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848 SkASSERT(rec && rec->fLayer);
849 return rec->fLayer->fDevice;
850}
851
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000852SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000853 if (updateMatrixClip) {
854 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
855 }
reed@google.com9266fed2011-03-30 00:18:03 +0000856 return fMCRec->fTopLayer->fDevice;
857}
858
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000859bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700860 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000861 return false;
862 }
863
864 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700865 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700866 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000867 return false;
868 }
869 weAllocated = true;
870 }
871
reedcf01e312015-05-23 19:14:51 -0700872 SkAutoPixmapUnlock unlocker;
873 if (bitmap->requestLock(&unlocker)) {
874 const SkPixmap& pm = unlocker.pixmap();
875 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
876 return true;
877 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000878 }
879
880 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700881 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000882 }
883 return false;
884}
reed@google.com51df9e32010-12-23 19:29:18 +0000885
bsalomon@google.comc6980972011-11-02 19:57:21 +0000886bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000887 SkIRect r = srcRect;
888 const SkISize size = this->getBaseLayerSize();
889 if (!r.intersect(0, 0, size.width(), size.height())) {
890 bitmap->reset();
891 return false;
892 }
893
reed84825042014-09-02 12:50:45 -0700894 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000895 // bitmap will already be reset.
896 return false;
897 }
898 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
899 bitmap->reset();
900 return false;
901 }
902 return true;
903}
904
reed96472de2014-12-10 09:53:42 -0800905bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000906 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000907 if (!device) {
908 return false;
909 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000910 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800911
reed96472de2014-12-10 09:53:42 -0800912 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
913 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000914 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000915 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000916
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000917 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800918 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000919}
920
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000921bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700922 SkAutoPixmapUnlock unlocker;
923 if (bitmap.requestLock(&unlocker)) {
924 const SkPixmap& pm = unlocker.pixmap();
925 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000926 }
927 return false;
928}
929
930bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
931 int x, int y) {
932 switch (origInfo.colorType()) {
933 case kUnknown_SkColorType:
934 case kIndex_8_SkColorType:
935 return false;
936 default:
937 break;
938 }
halcanary96fcdcc2015-08-27 07:41:13 -0700939 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000940 return false;
941 }
942
943 const SkISize size = this->getBaseLayerSize();
944 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
945 if (!target.intersect(0, 0, size.width(), size.height())) {
946 return false;
947 }
948
949 SkBaseDevice* device = this->getDevice();
950 if (!device) {
951 return false;
952 }
953
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000954 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700955 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000956
957 // if x or y are negative, then we have to adjust pixels
958 if (x > 0) {
959 x = 0;
960 }
961 if (y > 0) {
962 y = 0;
963 }
964 // here x,y are either 0 or negative
965 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
966
reed4af35f32014-06-27 17:47:49 -0700967 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700968 const bool completeOverwrite = info.dimensions() == size;
969 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700970
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000971 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000972 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000973}
reed@google.com51df9e32010-12-23 19:29:18 +0000974
junov@google.com4370aed2012-01-18 16:21:08 +0000975SkCanvas* SkCanvas::canvasForDrawIter() {
976 return this;
977}
978
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979//////////////////////////////////////////////////////////////////////////////
980
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981void SkCanvas::updateDeviceCMCache() {
982 if (fDeviceCMDirty) {
983 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700984 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000985 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000986
halcanary96fcdcc2015-08-27 07:41:13 -0700987 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700988 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000990 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991 do {
reedde6c5312016-09-02 12:10:07 -0700992 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700993 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994 }
995 fDeviceCMDirty = false;
996 }
997}
998
reed@android.com8a1c16f2008-12-17 15:59:43 +0000999///////////////////////////////////////////////////////////////////////////////
1000
reed2ff1fce2014-12-11 07:07:37 -08001001void SkCanvas::checkForDeferredSave() {
1002 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -08001003 this->doSave();
1004 }
1005}
1006
reedf0090cb2014-11-26 08:55:51 -08001007int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -08001008#ifdef SK_DEBUG
1009 int count = 0;
1010 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1011 for (;;) {
1012 const MCRec* rec = (const MCRec*)iter.next();
1013 if (!rec) {
1014 break;
1015 }
1016 count += 1 + rec->fDeferredSaveCount;
1017 }
1018 SkASSERT(count == fSaveCount);
1019#endif
1020 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001021}
1022
1023int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001024 fSaveCount += 1;
1025 fMCRec->fDeferredSaveCount += 1;
1026 return this->getSaveCount() - 1; // return our prev value
1027}
1028
1029void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001030 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001031
1032 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1033 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001034 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001035}
1036
1037void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001038 if (fMCRec->fDeferredSaveCount > 0) {
1039 SkASSERT(fSaveCount > 1);
1040 fSaveCount -= 1;
1041 fMCRec->fDeferredSaveCount -= 1;
1042 } else {
1043 // check for underflow
1044 if (fMCStack.count() > 1) {
1045 this->willRestore();
1046 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001047 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001048 this->internalRestore();
1049 this->didRestore();
1050 }
reedf0090cb2014-11-26 08:55:51 -08001051 }
1052}
1053
1054void SkCanvas::restoreToCount(int count) {
1055 // sanity check
1056 if (count < 1) {
1057 count = 1;
1058 }
mtkleinf0f14112014-12-12 08:46:25 -08001059
reedf0090cb2014-11-26 08:55:51 -08001060 int n = this->getSaveCount() - count;
1061 for (int i = 0; i < n; ++i) {
1062 this->restore();
1063 }
1064}
1065
reed2ff1fce2014-12-11 07:07:37 -08001066void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001068 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001070
reed687fa1c2015-04-07 08:00:56 -07001071 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072}
1073
reed4960eee2015-12-18 07:09:18 -08001074bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001075 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001076}
1077
reed4960eee2015-12-18 07:09:18 -08001078bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001079 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001080 SkIRect clipBounds;
1081 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001082 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001083 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001084
reed96e657d2015-03-10 17:30:07 -07001085 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1086
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001087 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001088 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001089 if (bounds && !imageFilter->canComputeFastBounds()) {
1090 bounds = nullptr;
1091 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001092 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001093 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001094 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001096
reed96e657d2015-03-10 17:30:07 -07001097 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 r.roundOut(&ir);
1099 // early exit if the layer's bounds are clipped out
1100 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001101 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001102 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001103 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001104 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001105 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106 }
1107 } else { // no user bounds, so just use the clip
1108 ir = clipBounds;
1109 }
reed180aec42015-03-11 10:39:04 -07001110 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111
reed4960eee2015-12-18 07:09:18 -08001112 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001113 // Simplify the current clips since they will be applied properly during restore()
reed687fa1c2015-04-07 08:00:56 -07001114 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001115 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001116 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001117 }
1118
1119 if (intersection) {
1120 *intersection = ir;
1121 }
1122 return true;
1123}
1124
reed4960eee2015-12-18 07:09:18 -08001125
reed4960eee2015-12-18 07:09:18 -08001126int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1127 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001128}
1129
reed70ee31b2015-12-10 13:44:45 -08001130int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001131 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1132}
1133
1134int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1135 SaveLayerRec rec(origRec);
1136 if (gIgnoreSaveLayerBounds) {
1137 rec.fBounds = nullptr;
1138 }
1139 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1140 fSaveCount += 1;
1141 this->internalSaveLayer(rec, strategy);
1142 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001143}
1144
reeda2217ef2016-07-20 06:04:34 -07001145void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1146 SkBaseDevice* dst, const SkMatrix& ctm,
1147 const SkClipStack* clipStack) {
1148 SkDraw draw;
1149 SkRasterClip rc;
1150 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1151 if (!dst->accessPixels(&draw.fDst)) {
1152 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001153 }
reeda2217ef2016-07-20 06:04:34 -07001154 draw.fMatrix = &SkMatrix::I();
1155 draw.fRC = &rc;
1156 draw.fClipStack = clipStack;
1157 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001158
1159 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001160 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001161
1162 int x = src->getOrigin().x() - dst->getOrigin().x();
1163 int y = src->getOrigin().y() - dst->getOrigin().y();
1164 auto special = src->snapSpecial();
1165 if (special) {
1166 dst->drawSpecial(draw, special.get(), x, y, p);
1167 }
robertphillips7354a4b2015-12-16 05:08:27 -08001168}
reed70ee31b2015-12-10 13:44:45 -08001169
reed129ed1c2016-02-22 06:42:31 -08001170static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1171 const SkPaint* paint) {
1172 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1173 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001174 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001175 const bool hasImageFilter = paint && paint->getImageFilter();
1176
1177 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1178 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1179 // force to L32
1180 return SkImageInfo::MakeN32(w, h, alphaType);
1181 } else {
1182 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001183 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001184 }
1185}
1186
reed4960eee2015-12-18 07:09:18 -08001187void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1188 const SkRect* bounds = rec.fBounds;
1189 const SkPaint* paint = rec.fPaint;
1190 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1191
reed8c30a812016-04-20 16:36:51 -07001192 SkLazyPaint lazyP;
1193 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1194 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001195 SkMatrix remainder;
1196 SkSize scale;
1197 /*
1198 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1199 * but they do handle scaling. To accommodate this, we do the following:
1200 *
1201 * 1. Stash off the current CTM
1202 * 2. Decompose the CTM into SCALE and REMAINDER
1203 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1204 * contains the REMAINDER
1205 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1206 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1207 * of the original imagefilter, and draw that (via drawSprite)
1208 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1209 *
1210 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1211 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1212 */
reed96a04f32016-04-25 09:25:15 -07001213 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001214 stashedMatrix.decomposeScale(&scale, &remainder))
1215 {
1216 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1217 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1218 SkPaint* p = lazyP.set(*paint);
1219 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1220 SkFilterQuality::kLow_SkFilterQuality,
1221 sk_ref_sp(imageFilter)));
1222 imageFilter = p->getImageFilter();
1223 paint = p;
1224 }
reed8c30a812016-04-20 16:36:51 -07001225
junov@chromium.orga907ac32012-02-24 21:54:07 +00001226 // do this before we create the layer. We don't call the public save() since
1227 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001228 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001229
1230 fDeviceCMDirty = true;
1231
1232 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001233 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001234 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001235 }
1236
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001237 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1238 // the clipRectBounds() call above?
1239 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001240 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001241 }
1242
reed4960eee2015-12-18 07:09:18 -08001243 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001244 SkPixelGeometry geo = fProps.pixelGeometry();
1245 if (paint) {
reed76033be2015-03-14 10:54:31 -07001246 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001247 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001248 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001249 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001250 }
1251 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001252
robertphillips5139e502016-07-19 05:10:40 -07001253 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001254 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001255 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001256 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001257 }
reedb2db8982014-11-13 12:41:02 -08001258
robertphillips5139e502016-07-19 05:10:40 -07001259 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001260 paint);
1261
robertphillips5139e502016-07-19 05:10:40 -07001262 SkAutoTUnref<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001263 {
reed70ee31b2015-12-10 13:44:45 -08001264 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001265 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001266 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001267 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
reedcd4051e2016-07-15 09:41:26 -07001268 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001269 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1270 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001271 SkErrorInternals::SetError(kInternalError_SkError,
1272 "Unable to create device for layer.");
1273 return;
reed61f501f2015-04-29 08:34:00 -07001274 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001275 }
robertphillips5139e502016-07-19 05:10:40 -07001276 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001277
robertphillips5139e502016-07-19 05:10:40 -07001278 DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279
1280 layer->fNext = fMCRec->fTopLayer;
1281 fMCRec->fLayer = layer;
1282 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001283
1284 if (rec.fBackdrop) {
1285 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice,
1286 fMCRec->fMatrix, this->getClipStack());
1287 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288}
1289
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001290int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001291 if (0xFF == alpha) {
1292 return this->saveLayer(bounds, nullptr);
1293 } else {
1294 SkPaint tmpPaint;
1295 tmpPaint.setAlpha(alpha);
1296 return this->saveLayer(bounds, &tmpPaint);
1297 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001298}
1299
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300void SkCanvas::internalRestore() {
1301 SkASSERT(fMCStack.count() != 0);
1302
1303 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001304
reed687fa1c2015-04-07 08:00:56 -07001305 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001306
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001307 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308 DeviceCM* layer = fMCRec->fLayer; // may be null
1309 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001310 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311
1312 // now do the normal restore()
1313 fMCRec->~MCRec(); // balanced in save()
1314 fMCStack.pop_back();
1315 fMCRec = (MCRec*)fMCStack.back();
1316
1317 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1318 since if we're being recorded, we don't want to record this (the
1319 recorder will have already recorded the restore).
1320 */
bsalomon49f085d2014-09-05 13:34:00 -07001321 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001323 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001324 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001325 // restore what we smashed in internalSaveLayer
1326 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001327 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001329 delete layer;
reedb679ca82015-04-07 04:40:48 -07001330 } else {
1331 // we're at the root
reeda499f902015-05-01 09:34:31 -07001332 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001333 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001334 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001336 }
msarettfbfa2582016-08-12 08:29:08 -07001337
1338 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001339 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001340 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1341 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342}
1343
reede8f30622016-03-23 18:59:25 -07001344sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001345 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001346 props = &fProps;
1347 }
1348 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001349}
1350
reede8f30622016-03-23 18:59:25 -07001351sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001352 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001353 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001354}
1355
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001356SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001357 return this->onImageInfo();
1358}
1359
1360SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001361 SkBaseDevice* dev = this->getDevice();
1362 if (dev) {
1363 return dev->imageInfo();
1364 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001365 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001366 }
1367}
1368
brianosman898235c2016-04-06 07:38:23 -07001369bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001370 return this->onGetProps(props);
1371}
1372
1373bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001374 SkBaseDevice* dev = this->getDevice();
1375 if (dev) {
1376 if (props) {
1377 *props = fProps;
1378 }
1379 return true;
1380 } else {
1381 return false;
1382 }
1383}
1384
reed6ceeebd2016-03-09 14:26:26 -08001385#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001386const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001387 SkPixmap pmap;
reed6ceeebd2016-03-09 14:26:26 -08001388 if (this->peekPixels(&pmap)) {
1389 if (info) {
1390 *info = pmap.info();
1391 }
1392 if (rowBytes) {
1393 *rowBytes = pmap.rowBytes();
1394 }
1395 return pmap.addr();
reed884e97c2015-05-26 11:31:54 -07001396 }
reed6ceeebd2016-03-09 14:26:26 -08001397 return nullptr;
1398}
1399#endif
1400
1401bool SkCanvas::peekPixels(SkPixmap* pmap) {
1402 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001403}
1404
reed884e97c2015-05-26 11:31:54 -07001405bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001406 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001407 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001408}
1409
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001410void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001411 SkPixmap pmap;
1412 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001413 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001414 }
1415 if (info) {
1416 *info = pmap.info();
1417 }
1418 if (rowBytes) {
1419 *rowBytes = pmap.rowBytes();
1420 }
1421 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001422 *origin = this->getTopDevice(false)->getOrigin();
1423 }
reed884e97c2015-05-26 11:31:54 -07001424 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001425}
1426
reed884e97c2015-05-26 11:31:54 -07001427bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001428 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001429 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001430}
1431
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433
reed7503d602016-07-15 14:23:29 -07001434void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001435 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001436 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001437 paint = &tmp;
1438 }
reed@google.com4b226022011-01-11 18:32:13 +00001439
reed@google.com8926b162012-03-23 15:36:36 +00001440 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001441
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001443 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001444 paint = &looper.paint();
1445 SkImageFilter* filter = paint->getImageFilter();
1446 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
senorblancof35566e2016-04-18 10:32:02 -07001447 if (filter) {
reeda2217ef2016-07-20 06:04:34 -07001448 dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001449 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001450 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001451 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452 }
reeda2217ef2016-07-20 06:04:34 -07001453
reed@google.com4e2b3d32011-04-07 14:18:59 +00001454 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001455}
1456
reed32704672015-12-16 08:27:10 -08001457/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001458
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001459void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001460 if (dx || dy) {
1461 this->checkForDeferredSave();
1462 fDeviceCMDirty = true;
1463 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001464
reedfe69b502016-09-12 06:31:48 -07001465 // Translate shouldn't affect the is-scale-translateness of the matrix.
1466 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001467
reedfe69b502016-09-12 06:31:48 -07001468 this->didTranslate(dx,dy);
1469 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001470}
1471
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001472void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001473 SkMatrix m;
1474 m.setScale(sx, sy);
1475 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476}
1477
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001478void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001479 SkMatrix m;
1480 m.setRotate(degrees);
1481 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482}
1483
bungeman7438bfc2016-07-12 15:01:19 -07001484void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1485 SkMatrix m;
1486 m.setRotate(degrees, px, py);
1487 this->concat(m);
1488}
1489
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001490void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001491 SkMatrix m;
1492 m.setSkew(sx, sy);
1493 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001494}
1495
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001496void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001497 if (matrix.isIdentity()) {
1498 return;
1499 }
1500
reed2ff1fce2014-12-11 07:07:37 -08001501 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001502 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001503 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001504 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001505 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001506}
1507
reed8c30a812016-04-20 16:36:51 -07001508void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001509 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001510 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001511 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001512}
1513
1514void SkCanvas::setMatrix(const SkMatrix& matrix) {
1515 this->checkForDeferredSave();
1516 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001517 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001518}
1519
reed@android.com8a1c16f2008-12-17 15:59:43 +00001520void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001521 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001522}
1523
vjiaoblack95302da2016-07-21 10:25:54 -07001524#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001525void SkCanvas::translateZ(SkScalar z) {
1526 this->checkForDeferredSave();
1527 this->fMCRec->fCurDrawDepth += z;
1528 this->didTranslateZ(z);
1529}
1530
1531SkScalar SkCanvas::getZ() const {
1532 return this->fMCRec->fCurDrawDepth;
1533}
1534
vjiaoblack95302da2016-07-21 10:25:54 -07001535void SkCanvas::setLights(sk_sp<SkLights> lights) {
1536 this->fLights = lights;
1537}
1538
1539sk_sp<SkLights> SkCanvas::getLights() const {
1540 return this->fLights;
1541}
1542#endif
1543
reed@android.com8a1c16f2008-12-17 15:59:43 +00001544//////////////////////////////////////////////////////////////////////////////
1545
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001546void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2d1afab2016-06-29 14:33:11 -07001547 if (!fAllowSoftClip) {
1548 doAA = false;
1549 }
1550
1551#ifdef SK_SUPPORT_PRECHECK_CLIPRECT
1552 // Check if we can quick-accept the clip call (and do nothing)
1553 //
reed74467162016-06-30 08:15:35 -07001554 if (SkRegion::kIntersect_Op == op && !doAA && fMCRec->fMatrix.isScaleTranslate()) {
halcanaryc5769b22016-08-10 07:13:21 -07001555 SkRect devR;
1556 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reed2d1afab2016-06-29 14:33:11 -07001557 // NOTE: this check is CTM specific, since we might round differently with a different
1558 // CTM. Thus this is only 100% reliable if there is not global CTM scale to be
1559 // applied later (i.e. if this is going into a picture).
1560 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#endif
1569
reed2ff1fce2014-12-11 07:07:37 -08001570 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001571 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1572 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001573}
1574
1575void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001576#ifdef SK_ENABLE_CLIP_QUICKREJECT
1577 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001578 if (fMCRec->fRasterClip.isEmpty()) {
reed2d1afab2016-06-29 14:33:11 -07001579 return;
reed@google.comda17f752012-08-16 18:27:05 +00001580 }
1581
reed@google.com3b3e8952012-08-16 20:53:31 +00001582 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001583 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001584 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001585
reed687fa1c2015-04-07 08:00:56 -07001586 fClipStack->clipEmpty();
reed2d1afab2016-06-29 14:33:11 -07001587 (void)fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001588 fDeviceClipBounds.setEmpty();
reed2d1afab2016-06-29 14:33:11 -07001589 return;
reed@google.comda17f752012-08-16 18:27:05 +00001590 }
1591 }
1592#endif
1593
reed74467162016-06-30 08:15:35 -07001594 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate();
reedc64eff52015-11-21 12:39:45 -08001595 SkRect devR;
reed74467162016-06-30 08:15:35 -07001596 if (isScaleTrans) {
halcanaryc5769b22016-08-10 07:13:21 -07001597 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reedc64eff52015-11-21 12:39:45 -08001598 }
bsalomonac8cabd2015-11-20 18:53:07 -08001599
reed2d1afab2016-06-29 14:33:11 -07001600#ifndef SK_SUPPORT_PRECHECK_CLIPRECT
reedc64eff52015-11-21 12:39:45 -08001601 if (SkRegion::kIntersect_Op == op &&
1602 kHard_ClipEdgeStyle == edgeStyle
reed74467162016-06-30 08:15:35 -07001603 && isScaleTrans)
reedc64eff52015-11-21 12:39:45 -08001604 {
1605 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1606#if 0
1607 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1608 rect.left(), rect.top(), rect.right(), rect.bottom());
1609#endif
1610 return;
1611 }
1612 }
reed2d1afab2016-06-29 14:33:11 -07001613#endif
reedc64eff52015-11-21 12:39:45 -08001614
1615 AutoValidateClip avc(this);
1616
1617 fDeviceCMDirty = true;
reedc64eff52015-11-21 12:39:45 -08001618
reed74467162016-06-30 08:15:35 -07001619 if (isScaleTrans) {
reedc64eff52015-11-21 12:39:45 -08001620 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1621 fClipStack->clipDevRect(devR, op, isAA);
senorblancoafc7cce2016-02-02 18:44:15 -08001622 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001623 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001624 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001625 // and clip against that, since it can handle any matrix. However, to
1626 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1627 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001628 SkPath path;
1629
1630 path.addRect(rect);
bsalomonbdc335f2016-08-22 13:42:17 -07001631 path.setIsVolatile(true);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001632 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001633 }
msarettfbfa2582016-08-12 08:29:08 -07001634
1635 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001636}
1637
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001638void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001639 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001640 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001641 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001642 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1643 } else {
1644 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001645 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001646}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001647
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001648void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001649 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001650 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001651 AutoValidateClip avc(this);
1652
1653 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001654 if (!fAllowSoftClip) {
1655 edgeStyle = kHard_ClipEdgeStyle;
1656 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001657
reed687fa1c2015-04-07 08:00:56 -07001658 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001659
senorblancoafc7cce2016-02-02 18:44:15 -08001660 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
robertphillips125f19a2015-11-23 09:00:05 -08001661 kSoft_ClipEdgeStyle == edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001662 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001663 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001664 }
1665
1666 SkPath path;
1667 path.addRRect(rrect);
bsalomonbdc335f2016-08-22 13:42:17 -07001668 path.setIsVolatile(true);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001669 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001670 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001671}
1672
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001673void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001674 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001675 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001676
1677 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1678 SkRect r;
1679 if (path.isRect(&r)) {
1680 this->onClipRect(r, op, edgeStyle);
1681 return;
1682 }
1683 SkRRect rrect;
1684 if (path.isOval(&r)) {
1685 rrect.setOval(r);
1686 this->onClipRRect(rrect, op, edgeStyle);
1687 return;
1688 }
1689 if (path.isRRect(&rrect)) {
1690 this->onClipRRect(rrect, op, edgeStyle);
1691 return;
1692 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001693 }
robertphillips39f05382015-11-24 09:30:12 -08001694
1695 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001696}
1697
1698void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001699#ifdef SK_ENABLE_CLIP_QUICKREJECT
1700 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001701 if (fMCRec->fRasterClip.isEmpty()) {
reed2d1afab2016-06-29 14:33:11 -07001702 return;
reed@google.comda17f752012-08-16 18:27:05 +00001703 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001704
reed@google.com3b3e8952012-08-16 20:53:31 +00001705 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001706 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001707 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001708
reed687fa1c2015-04-07 08:00:56 -07001709 fClipStack->clipEmpty();
reed2d1afab2016-06-29 14:33:11 -07001710 (void)fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001711 fDeviceClipBounds.setEmpty();
reed2d1afab2016-06-29 14:33:11 -07001712 return;
reed@google.comda17f752012-08-16 18:27:05 +00001713 }
1714 }
1715#endif
1716
reed@google.com5c3d1472011-02-22 19:12:23 +00001717 AutoValidateClip avc(this);
1718
reed@android.com8a1c16f2008-12-17 15:59:43 +00001719 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001720 if (!fAllowSoftClip) {
1721 edgeStyle = kHard_ClipEdgeStyle;
1722 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001723
1724 SkPath devPath;
bsalomonbdc335f2016-08-22 13:42:17 -07001725 if (fMCRec->fMatrix.isIdentity()) {
1726 devPath = path;
1727 } else {
1728 path.transform(fMCRec->fMatrix, &devPath);
1729 devPath.setIsVolatile(true);
1730 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001731
reed@google.comfe701122011-11-08 19:41:23 +00001732 // Check if the transfomation, or the original path itself
1733 // made us empty. Note this can also happen if we contained NaN
1734 // values. computing the bounds detects this, and will set our
1735 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1736 if (devPath.getBounds().isEmpty()) {
1737 // resetting the path will remove any NaN or other wanky values
1738 // that might upset our scan converter.
1739 devPath.reset();
1740 }
1741
reed@google.com5c3d1472011-02-22 19:12:23 +00001742 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001743 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001744
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001745 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001746 bool clipIsAA = getClipStack()->asPath(&devPath);
1747 if (clipIsAA) {
1748 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001749 }
fmalita1a481fe2015-02-04 07:39:34 -08001750
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001751 op = SkRegion::kReplace_Op;
1752 }
1753
senorblancoafc7cce2016-02-02 18:44:15 -08001754 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001755 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001756}
1757
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001758void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001759 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001760 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001761}
1762
1763void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001764 AutoValidateClip avc(this);
1765
reed@android.com8a1c16f2008-12-17 15:59:43 +00001766 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001767
reed@google.com5c3d1472011-02-22 19:12:23 +00001768 // todo: signal fClipStack that we have a region, and therefore (I guess)
1769 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001770 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001771
reed1f836ee2014-07-07 07:49:34 -07001772 fMCRec->fRasterClip.op(rgn, op);
msarettfbfa2582016-08-12 08:29:08 -07001773 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001774}
1775
reed@google.com819c9212011-02-23 18:56:55 +00001776#ifdef SK_DEBUG
1777void SkCanvas::validateClip() const {
1778 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001779 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001780 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001781 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001782 return;
1783 }
1784
reed@google.com819c9212011-02-23 18:56:55 +00001785 SkIRect ir;
1786 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001787 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001788
reed687fa1c2015-04-07 08:00:56 -07001789 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001790 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001791 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001792 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001793 case SkClipStack::Element::kRect_Type:
1794 element->getRect().round(&ir);
1795 tmpClip.op(ir, element->getOp());
1796 break;
1797 case SkClipStack::Element::kEmpty_Type:
1798 tmpClip.setEmpty();
1799 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001800 default: {
1801 SkPath path;
1802 element->asPath(&path);
senorblancoafc7cce2016-02-02 18:44:15 -08001803 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001804 break;
1805 }
reed@google.com819c9212011-02-23 18:56:55 +00001806 }
1807 }
reed@google.com819c9212011-02-23 18:56:55 +00001808}
1809#endif
1810
reed@google.com90c07ea2012-04-13 13:50:27 +00001811void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001812 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001813 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001814
halcanary96fcdcc2015-08-27 07:41:13 -07001815 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001816 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001817 }
1818}
1819
reed@google.com5c3d1472011-02-22 19:12:23 +00001820///////////////////////////////////////////////////////////////////////////////
1821
reed@google.com754de5f2014-02-24 19:38:20 +00001822bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001823 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001824}
1825
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001826bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001827 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001828}
1829
msarettfbfa2582016-08-12 08:29:08 -07001830static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1831#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1832 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1833 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1834 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1835 return 0xF != _mm_movemask_ps(mask);
1836#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1837 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1838 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1839 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1840 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1841#else
1842 SkRect devRectAsRect;
1843 SkRect devClipAsRect;
1844 devRect.store(&devRectAsRect.fLeft);
1845 devClip.store(&devClipAsRect.fLeft);
1846 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1847#endif
1848}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001849
msarettfbfa2582016-08-12 08:29:08 -07001850// It's important for this function to not be inlined. Otherwise the compiler will share code
1851// between the fast path and the slow path, resulting in two slow paths.
1852static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1853 const SkMatrix& matrix) {
1854 SkRect deviceRect;
1855 matrix.mapRect(&deviceRect, src);
1856 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1857}
1858
1859bool SkCanvas::quickReject(const SkRect& src) const {
1860#ifdef SK_DEBUG
1861 // Verify that fDeviceClipBounds are set properly.
1862 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001863 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001864 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001865 } else {
msarettfbfa2582016-08-12 08:29:08 -07001866 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001867 }
msarettfbfa2582016-08-12 08:29:08 -07001868
msarett9637ea92016-08-18 14:03:30 -07001869 // Verify that fIsScaleTranslate is set properly.
1870 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001871#endif
1872
msarett9637ea92016-08-18 14:03:30 -07001873 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001874 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1875 }
1876
1877 // We inline the implementation of mapScaleTranslate() for the fast path.
1878 float sx = fMCRec->fMatrix.getScaleX();
1879 float sy = fMCRec->fMatrix.getScaleY();
1880 float tx = fMCRec->fMatrix.getTranslateX();
1881 float ty = fMCRec->fMatrix.getTranslateY();
1882 Sk4f scale(sx, sy, sx, sy);
1883 Sk4f trans(tx, ty, tx, ty);
1884
1885 // Apply matrix.
1886 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1887
1888 // Make sure left < right, top < bottom.
1889 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1890 Sk4f min = Sk4f::Min(ltrb, rblt);
1891 Sk4f max = Sk4f::Max(ltrb, rblt);
1892 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1893 // ARM this sequence generates the fastest (a single instruction).
1894 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1895
1896 // Check if the device rect is NaN or outside the clip.
1897 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001898}
1899
reed@google.com3b3e8952012-08-16 20:53:31 +00001900bool SkCanvas::quickReject(const SkPath& path) const {
1901 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001902}
1903
reed@google.com3b3e8952012-08-16 20:53:31 +00001904bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001905 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001906 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001907 return false;
1908 }
1909
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001910 SkMatrix inverse;
1911 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001912 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001913 if (bounds) {
1914 bounds->setEmpty();
1915 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001916 return false;
1917 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001918
bsalomon49f085d2014-09-05 13:34:00 -07001919 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001920 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001921 // adjust it outwards in case we are antialiasing
1922 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001923
reed@google.com8f4d2302013-12-17 16:44:46 +00001924 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1925 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001926 inverse.mapRect(bounds, r);
1927 }
1928 return true;
1929}
1930
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001931bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001932 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001933 if (clip.isEmpty()) {
1934 if (bounds) {
1935 bounds->setEmpty();
1936 }
1937 return false;
1938 }
1939
bsalomon49f085d2014-09-05 13:34:00 -07001940 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001941 *bounds = clip.getBounds();
1942 }
1943 return true;
1944}
1945
reed@android.com8a1c16f2008-12-17 15:59:43 +00001946const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001947 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001948}
1949
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001950const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001951 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001952}
1953
robertphillips175dd9b2016-04-28 14:32:04 -07001954GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001955 SkBaseDevice* dev = this->getTopDevice();
robertphillips175dd9b2016-04-28 14:32:04 -07001956 return dev ? dev->accessDrawContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001957}
1958
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001959GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001960 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001961 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001962}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001963
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001964void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1965 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001966 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001967 if (outer.isEmpty()) {
1968 return;
1969 }
1970 if (inner.isEmpty()) {
1971 this->drawRRect(outer, paint);
1972 return;
1973 }
1974
1975 // We don't have this method (yet), but technically this is what we should
1976 // be able to assert...
1977 // SkASSERT(outer.contains(inner));
1978 //
1979 // For now at least check for containment of bounds
1980 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1981
1982 this->onDrawDRRect(outer, inner, paint);
1983}
1984
reed41af9662015-01-05 07:49:08 -08001985// These need to stop being virtual -- clients need to override the onDraw... versions
1986
1987void SkCanvas::drawPaint(const SkPaint& paint) {
1988 this->onDrawPaint(paint);
1989}
1990
1991void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1992 this->onDrawRect(r, paint);
1993}
1994
msarettdca352e2016-08-26 06:37:45 -07001995void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1996 if (region.isEmpty()) {
1997 return;
1998 }
1999
2000 if (region.isRect()) {
2001 return this->drawIRect(region.getBounds(), paint);
2002 }
2003
2004 this->onDrawRegion(region, paint);
2005}
2006
reed41af9662015-01-05 07:49:08 -08002007void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
2008 this->onDrawOval(r, paint);
2009}
2010
2011void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
2012 this->onDrawRRect(rrect, paint);
2013}
2014
2015void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
2016 this->onDrawPoints(mode, count, pts, paint);
2017}
2018
2019void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
2020 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
2021 const uint16_t indices[], int indexCount, const SkPaint& paint) {
2022 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
2023 indices, indexCount, paint);
2024}
2025
2026void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
2027 this->onDrawPath(path, paint);
2028}
2029
reeda85d4d02015-05-06 12:56:48 -07002030void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002031 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07002032 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08002033}
2034
reede47829b2015-08-06 10:02:53 -07002035void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
2036 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002037 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002038 if (dst.isEmpty() || src.isEmpty()) {
2039 return;
2040 }
2041 this->onDrawImageRect(image, &src, dst, paint, constraint);
2042}
reed41af9662015-01-05 07:49:08 -08002043
reed84984ef2015-07-17 07:09:43 -07002044void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
2045 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002046 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002047 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002048}
2049
reede47829b2015-08-06 10:02:53 -07002050void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
2051 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002052 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002053 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
2054 constraint);
2055}
reede47829b2015-08-06 10:02:53 -07002056
reed4c21dc52015-06-25 12:32:03 -07002057void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2058 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002059 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07002060 if (dst.isEmpty()) {
2061 return;
2062 }
msarett552bca92016-08-03 06:53:26 -07002063 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2064 this->onDrawImageNine(image, center, dst, paint);
2065 } else {
reede47829b2015-08-06 10:02:53 -07002066 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002067 }
reed4c21dc52015-06-25 12:32:03 -07002068}
2069
msarett16882062016-08-16 09:31:08 -07002070void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2071 const SkPaint* paint) {
2072 RETURN_ON_NULL(image);
2073 if (dst.isEmpty()) {
2074 return;
2075 }
2076 if (SkLatticeIter::Valid(image->width(), image->height(), lattice)) {
2077 this->onDrawImageLattice(image, lattice, dst, paint);
2078 } else {
2079 this->drawImageRect(image, dst, paint);
2080 }
2081}
2082
reed41af9662015-01-05 07:49:08 -08002083void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002084 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002085 return;
2086 }
reed41af9662015-01-05 07:49:08 -08002087 this->onDrawBitmap(bitmap, dx, dy, paint);
2088}
2089
reede47829b2015-08-06 10:02:53 -07002090void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002091 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002092 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002093 return;
2094 }
reede47829b2015-08-06 10:02:53 -07002095 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002096}
2097
reed84984ef2015-07-17 07:09:43 -07002098void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2099 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002100 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002101}
2102
reede47829b2015-08-06 10:02:53 -07002103void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2104 SrcRectConstraint constraint) {
2105 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2106 constraint);
2107}
reede47829b2015-08-06 10:02:53 -07002108
reed41af9662015-01-05 07:49:08 -08002109void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2110 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002111 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002112 return;
2113 }
msarett552bca92016-08-03 06:53:26 -07002114 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2115 this->onDrawBitmapNine(bitmap, center, dst, paint);
2116 } else {
reeda5517e22015-07-14 10:54:12 -07002117 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002118 }
reed41af9662015-01-05 07:49:08 -08002119}
2120
msarettc573a402016-08-02 08:05:56 -07002121void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2122 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002123 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002124 return;
2125 }
msarett16882062016-08-16 09:31:08 -07002126 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), lattice)) {
2127 this->onDrawBitmapLattice(bitmap, lattice, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002128 } else {
msarett16882062016-08-16 09:31:08 -07002129 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002130 }
msarettc573a402016-08-02 08:05:56 -07002131}
2132
reed71c3c762015-06-24 10:29:17 -07002133void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2134 const SkColor colors[], int count, SkXfermode::Mode mode,
2135 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002136 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002137 if (count <= 0) {
2138 return;
2139 }
2140 SkASSERT(atlas);
2141 SkASSERT(xform);
2142 SkASSERT(tex);
2143 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2144}
2145
reedf70b5312016-03-04 16:36:20 -08002146void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2147 if (key) {
2148 this->onDrawAnnotation(rect, key, value);
2149 }
2150}
2151
reede47829b2015-08-06 10:02:53 -07002152void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2153 const SkPaint* paint, SrcRectConstraint constraint) {
2154 if (src) {
2155 this->drawImageRect(image, *src, dst, paint, constraint);
2156 } else {
2157 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2158 dst, paint, constraint);
2159 }
2160}
2161void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2162 const SkPaint* paint, SrcRectConstraint constraint) {
2163 if (src) {
2164 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2165 } else {
2166 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2167 dst, paint, constraint);
2168 }
2169}
2170
tomhudsoncb3bd182016-05-18 07:24:16 -07002171void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2172 SkIRect layer_bounds = this->getTopLayerBounds();
2173 if (matrix) {
2174 *matrix = this->getTotalMatrix();
2175 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2176 }
2177 if (clip_bounds) {
2178 this->getClipDeviceBounds(clip_bounds);
2179 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2180 }
2181}
2182
reed@android.com8a1c16f2008-12-17 15:59:43 +00002183//////////////////////////////////////////////////////////////////////////////
2184// These are the virtual drawing methods
2185//////////////////////////////////////////////////////////////////////////////
2186
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002187void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002188 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002189 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2190 }
2191}
2192
reed41af9662015-01-05 07:49:08 -08002193void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002194 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002195 this->internalDrawPaint(paint);
2196}
2197
2198void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002199 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002200
2201 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002202 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002203 }
2204
reed@google.com4e2b3d32011-04-07 14:18:59 +00002205 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002206}
2207
reed41af9662015-01-05 07:49:08 -08002208void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2209 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002210 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002211 if ((long)count <= 0) {
2212 return;
2213 }
2214
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002215 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002216 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002217 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002218 // special-case 2 points (common for drawing a single line)
2219 if (2 == count) {
2220 r.set(pts[0], pts[1]);
2221 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002222 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002223 }
senorblanco87e066e2015-10-28 11:23:36 -07002224 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2225 return;
2226 }
2227 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002228 }
reed@google.coma584aed2012-05-16 14:06:02 +00002229
halcanary96fcdcc2015-08-27 07:41:13 -07002230 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002231
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002232 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002233
reed@android.com8a1c16f2008-12-17 15:59:43 +00002234 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002235 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002236 }
reed@google.com4b226022011-01-11 18:32:13 +00002237
reed@google.com4e2b3d32011-04-07 14:18:59 +00002238 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002239}
2240
reed4a167172016-08-18 17:15:25 -07002241static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2242 return ((intptr_t)paint.getImageFilter() |
2243#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2244 (intptr_t)canvas->getDrawFilter() |
2245#endif
2246 (intptr_t)paint.getLooper() ) != 0;
2247}
2248
reed41af9662015-01-05 07:49:08 -08002249void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002250 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002251 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002252 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002253 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002254 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2255 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2256 SkRect tmp(r);
2257 tmp.sort();
2258
senorblanco87e066e2015-10-28 11:23:36 -07002259 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2260 return;
2261 }
2262 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002263 }
reed@google.com4b226022011-01-11 18:32:13 +00002264
reed4a167172016-08-18 17:15:25 -07002265 if (needs_autodrawlooper(this, paint)) {
2266 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002267
reed4a167172016-08-18 17:15:25 -07002268 while (iter.next()) {
2269 iter.fDevice->drawRect(iter, r, looper.paint());
2270 }
2271
2272 LOOPER_END
2273 } else {
2274 this->predrawNotify(bounds, &paint, false);
2275 SkDrawIter iter(this);
2276 while (iter.next()) {
2277 iter.fDevice->drawRect(iter, r, paint);
2278 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002279 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002280}
2281
msarett44df6512016-08-25 13:54:30 -07002282void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2283 SkRect storage;
2284 SkRect regionRect = SkRect::Make(region.getBounds());
2285 const SkRect* bounds = nullptr;
2286 if (paint.canComputeFastBounds()) {
2287 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2288 return;
2289 }
2290 bounds = &regionRect;
2291 }
2292
2293 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2294
2295 while (iter.next()) {
2296 iter.fDevice->drawRegion(iter, region, looper.paint());
2297 }
2298
2299 LOOPER_END
2300}
2301
reed41af9662015-01-05 07:49:08 -08002302void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002303 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002304 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002305 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002306 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002307 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2308 return;
2309 }
2310 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002311 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002312
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002313 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002314
2315 while (iter.next()) {
2316 iter.fDevice->drawOval(iter, oval, looper.paint());
2317 }
2318
2319 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002320}
2321
bsalomonac3aa242016-08-19 11:25:19 -07002322void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2323 SkScalar sweepAngle, bool useCenter,
2324 const SkPaint& paint) {
2325 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2326 const SkRect* bounds = nullptr;
2327 if (paint.canComputeFastBounds()) {
2328 SkRect storage;
2329 // Note we're using the entire oval as the bounds.
2330 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2331 return;
2332 }
2333 bounds = &oval;
2334 }
2335
2336 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2337
2338 while (iter.next()) {
2339 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2340 }
2341
2342 LOOPER_END
2343}
2344
reed41af9662015-01-05 07:49:08 -08002345void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002346 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002347 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002348 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002349 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002350 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2351 return;
2352 }
2353 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002354 }
2355
2356 if (rrect.isRect()) {
2357 // call the non-virtual version
2358 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002359 return;
2360 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002361 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002362 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2363 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002364 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002365
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002366 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002367
2368 while (iter.next()) {
2369 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2370 }
2371
2372 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002373}
2374
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002375void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2376 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002377 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002378 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002379 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002380 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2381 return;
2382 }
2383 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002384 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002385
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002386 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002387
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002388 while (iter.next()) {
2389 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2390 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002391
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002392 LOOPER_END
2393}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002394
reed41af9662015-01-05 07:49:08 -08002395void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002396 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002397 if (!path.isFinite()) {
2398 return;
2399 }
2400
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002401 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002402 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002403 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002404 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002405 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2406 return;
2407 }
2408 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002409 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002410
2411 const SkRect& r = path.getBounds();
2412 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002413 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002414 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002415 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002416 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002417 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002418
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002419 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002420
2421 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002422 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002423 }
2424
reed@google.com4e2b3d32011-04-07 14:18:59 +00002425 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002426}
2427
reed262a71b2015-12-05 13:07:27 -08002428bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002429 if (!paint.getImageFilter()) {
2430 return false;
2431 }
2432
2433 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002434 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002435 return false;
2436 }
2437
2438 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2439 // Once we can filter and the filter will return a result larger than itself, we should be
2440 // able to remove this constraint.
2441 // skbug.com/4526
2442 //
2443 SkPoint pt;
2444 ctm.mapXY(x, y, &pt);
2445 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2446 return ir.contains(fMCRec->fRasterClip.getBounds());
2447}
2448
reeda85d4d02015-05-06 12:56:48 -07002449void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002450 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002451 SkRect bounds = SkRect::MakeXYWH(x, y,
2452 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002453 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002454 SkRect tmp = bounds;
2455 if (paint) {
2456 paint->computeFastBounds(tmp, &tmp);
2457 }
2458 if (this->quickReject(tmp)) {
2459 return;
2460 }
reeda85d4d02015-05-06 12:56:48 -07002461 }
halcanary9d524f22016-03-29 09:03:52 -07002462
reeda85d4d02015-05-06 12:56:48 -07002463 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002464 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002465 paint = lazy.init();
2466 }
reed262a71b2015-12-05 13:07:27 -08002467
reeda2217ef2016-07-20 06:04:34 -07002468 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002469 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2470 *paint);
2471 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002472 special = this->getDevice()->makeSpecial(image);
2473 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002474 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002475 }
2476 }
2477
reed262a71b2015-12-05 13:07:27 -08002478 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2479
reeda85d4d02015-05-06 12:56:48 -07002480 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002481 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002482 if (special) {
2483 SkPoint pt;
2484 iter.fMatrix->mapXY(x, y, &pt);
2485 iter.fDevice->drawSpecial(iter, special.get(),
2486 SkScalarRoundToInt(pt.fX),
2487 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002488 } else {
2489 iter.fDevice->drawImage(iter, image, x, y, pnt);
2490 }
reeda85d4d02015-05-06 12:56:48 -07002491 }
halcanary9d524f22016-03-29 09:03:52 -07002492
reeda85d4d02015-05-06 12:56:48 -07002493 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002494}
2495
reed41af9662015-01-05 07:49:08 -08002496void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002497 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002498 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002499 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002500 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002501 if (paint) {
2502 paint->computeFastBounds(dst, &storage);
2503 }
2504 if (this->quickReject(storage)) {
2505 return;
2506 }
reeda85d4d02015-05-06 12:56:48 -07002507 }
2508 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002509 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002510 paint = lazy.init();
2511 }
halcanary9d524f22016-03-29 09:03:52 -07002512
senorblancoc41e7e12015-12-07 12:51:30 -08002513 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002514 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002515
reeda85d4d02015-05-06 12:56:48 -07002516 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002517 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002518 }
halcanary9d524f22016-03-29 09:03:52 -07002519
reeda85d4d02015-05-06 12:56:48 -07002520 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002521}
2522
reed41af9662015-01-05 07:49:08 -08002523void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002524 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002525 SkDEBUGCODE(bitmap.validate();)
2526
reed33366972015-10-08 09:22:02 -07002527 if (bitmap.drawsNothing()) {
2528 return;
2529 }
2530
2531 SkLazyPaint lazy;
2532 if (nullptr == paint) {
2533 paint = lazy.init();
2534 }
2535
2536 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2537
2538 SkRect storage;
2539 const SkRect* bounds = nullptr;
2540 if (paint->canComputeFastBounds()) {
2541 bitmap.getBounds(&storage);
2542 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002543 SkRect tmp = storage;
2544 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2545 return;
2546 }
2547 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002548 }
reed@google.com4b226022011-01-11 18:32:13 +00002549
reeda2217ef2016-07-20 06:04:34 -07002550 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002551 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2552 *paint);
2553 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002554 special = this->getDevice()->makeSpecial(bitmap);
2555 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002556 drawAsSprite = false;
2557 }
2558 }
2559
reed262a71b2015-12-05 13:07:27 -08002560 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002561
2562 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002563 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002564 if (special) {
reed262a71b2015-12-05 13:07:27 -08002565 SkPoint pt;
2566 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002567 iter.fDevice->drawSpecial(iter, special.get(),
2568 SkScalarRoundToInt(pt.fX),
2569 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002570 } else {
2571 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2572 }
reed33366972015-10-08 09:22:02 -07002573 }
msarettfbfa2582016-08-12 08:29:08 -07002574
reed33366972015-10-08 09:22:02 -07002575 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002576}
2577
reed@google.com9987ec32011-09-07 11:57:52 +00002578// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002579void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002580 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002581 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002582 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002583 return;
2584 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002585
halcanary96fcdcc2015-08-27 07:41:13 -07002586 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002587 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002588 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2589 return;
2590 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002591 }
reed@google.com3d608122011-11-21 15:16:16 +00002592
reed@google.com33535f32012-09-25 15:37:50 +00002593 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002594 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002595 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002596 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002597
senorblancoc41e7e12015-12-07 12:51:30 -08002598 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002599 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002600
reed@google.com33535f32012-09-25 15:37:50 +00002601 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002602 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002603 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002604
reed@google.com33535f32012-09-25 15:37:50 +00002605 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002606}
2607
reed41af9662015-01-05 07:49:08 -08002608void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002609 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002610 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002611 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002612 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002613}
2614
reed4c21dc52015-06-25 12:32:03 -07002615void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2616 const SkPaint* paint) {
2617 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002618
halcanary96fcdcc2015-08-27 07:41:13 -07002619 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002620 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002621 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2622 return;
2623 }
reed@google.com3d608122011-11-21 15:16:16 +00002624 }
halcanary9d524f22016-03-29 09:03:52 -07002625
reed4c21dc52015-06-25 12:32:03 -07002626 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002627 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002628 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002629 }
halcanary9d524f22016-03-29 09:03:52 -07002630
senorblancoc41e7e12015-12-07 12:51:30 -08002631 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002632
reed4c21dc52015-06-25 12:32:03 -07002633 while (iter.next()) {
2634 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002635 }
halcanary9d524f22016-03-29 09:03:52 -07002636
reed4c21dc52015-06-25 12:32:03 -07002637 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002638}
2639
reed41af9662015-01-05 07:49:08 -08002640void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2641 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002642 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002643 SkDEBUGCODE(bitmap.validate();)
2644
halcanary96fcdcc2015-08-27 07:41:13 -07002645 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002646 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002647 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2648 return;
2649 }
reed4c21dc52015-06-25 12:32:03 -07002650 }
halcanary9d524f22016-03-29 09:03:52 -07002651
reed4c21dc52015-06-25 12:32:03 -07002652 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002653 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002654 paint = lazy.init();
2655 }
halcanary9d524f22016-03-29 09:03:52 -07002656
senorblancoc41e7e12015-12-07 12:51:30 -08002657 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002658
reed4c21dc52015-06-25 12:32:03 -07002659 while (iter.next()) {
2660 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2661 }
halcanary9d524f22016-03-29 09:03:52 -07002662
reed4c21dc52015-06-25 12:32:03 -07002663 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002664}
2665
msarett16882062016-08-16 09:31:08 -07002666void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2667 const SkPaint* paint) {
2668 if (nullptr == paint || paint->canComputeFastBounds()) {
2669 SkRect storage;
2670 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2671 return;
2672 }
2673 }
2674
2675 SkLazyPaint lazy;
2676 if (nullptr == paint) {
2677 paint = lazy.init();
2678 }
2679
2680 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2681
2682 while (iter.next()) {
2683 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2684 }
2685
2686 LOOPER_END
2687}
2688
2689void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2690 const SkRect& dst, const SkPaint* paint) {
2691 if (nullptr == paint || paint->canComputeFastBounds()) {
2692 SkRect storage;
2693 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2694 return;
2695 }
2696 }
2697
2698 SkLazyPaint lazy;
2699 if (nullptr == paint) {
2700 paint = lazy.init();
2701 }
2702
2703 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2704
2705 while (iter.next()) {
2706 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2707 }
2708
2709 LOOPER_END
2710}
2711
reed@google.comf67e4cf2011-03-15 20:56:58 +00002712class SkDeviceFilteredPaint {
2713public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002714 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002715 uint32_t filteredFlags = device->filterTextFlags(paint);
2716 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002717 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002718 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002719 fPaint = newPaint;
2720 } else {
2721 fPaint = &paint;
2722 }
2723 }
2724
reed@google.comf67e4cf2011-03-15 20:56:58 +00002725 const SkPaint& paint() const { return *fPaint; }
2726
2727private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002728 const SkPaint* fPaint;
2729 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002730};
2731
bungeman@google.com52c748b2011-08-22 21:30:43 +00002732void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2733 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002734 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002735 draw.fDevice->drawRect(draw, r, paint);
2736 } else {
2737 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002738 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002739 draw.fDevice->drawRect(draw, r, p);
2740 }
2741}
2742
2743void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2744 const char text[], size_t byteLength,
2745 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002746 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002747
2748 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002749 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002750 draw.fRC->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002751 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002752 return;
2753 }
2754
2755 SkScalar width = 0;
2756 SkPoint start;
2757
2758 start.set(0, 0); // to avoid warning
2759 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2760 SkPaint::kStrikeThruText_Flag)) {
2761 width = paint.measureText(text, byteLength);
2762
2763 SkScalar offsetX = 0;
2764 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2765 offsetX = SkScalarHalf(width);
2766 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2767 offsetX = width;
2768 }
2769 start.set(x - offsetX, y);
2770 }
2771
2772 if (0 == width) {
2773 return;
2774 }
2775
2776 uint32_t flags = paint.getFlags();
2777
2778 if (flags & (SkPaint::kUnderlineText_Flag |
2779 SkPaint::kStrikeThruText_Flag)) {
2780 SkScalar textSize = paint.getTextSize();
2781 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2782 SkRect r;
2783
2784 r.fLeft = start.fX;
2785 r.fRight = start.fX + width;
2786
2787 if (flags & SkPaint::kUnderlineText_Flag) {
2788 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2789 start.fY);
2790 r.fTop = offset;
2791 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002792 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002793 }
2794 if (flags & SkPaint::kStrikeThruText_Flag) {
2795 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2796 start.fY);
2797 r.fTop = offset;
2798 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002799 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002800 }
2801 }
2802}
2803
reed@google.come0d9ce82014-04-23 04:00:17 +00002804void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2805 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002806 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807
2808 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002809 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002810 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002811 DrawTextDecorations(iter, dfp.paint(),
2812 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002813 }
2814
reed@google.com4e2b3d32011-04-07 14:18:59 +00002815 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816}
2817
reed@google.come0d9ce82014-04-23 04:00:17 +00002818void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2819 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002820 SkPoint textOffset = SkPoint::Make(0, 0);
2821
halcanary96fcdcc2015-08-27 07:41:13 -07002822 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002823
reed@android.com8a1c16f2008-12-17 15:59:43 +00002824 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002825 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002826 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002827 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002829
reed@google.com4e2b3d32011-04-07 14:18:59 +00002830 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831}
2832
reed@google.come0d9ce82014-04-23 04:00:17 +00002833void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2834 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002835
2836 SkPoint textOffset = SkPoint::Make(0, constY);
2837
halcanary96fcdcc2015-08-27 07:41:13 -07002838 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002839
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002841 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002842 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002843 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002844 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002845
reed@google.com4e2b3d32011-04-07 14:18:59 +00002846 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847}
2848
reed@google.come0d9ce82014-04-23 04:00:17 +00002849void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2850 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002851 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002852
reed@android.com8a1c16f2008-12-17 15:59:43 +00002853 while (iter.next()) {
2854 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002855 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002856 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002857
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002858 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002859}
2860
reed45561a02016-07-07 12:47:17 -07002861void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2862 const SkRect* cullRect, const SkPaint& paint) {
2863 if (cullRect && this->quickReject(*cullRect)) {
2864 return;
2865 }
2866
2867 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2868
2869 while (iter.next()) {
2870 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2871 }
2872
2873 LOOPER_END
2874}
2875
fmalita00d5c2c2014-08-21 08:53:26 -07002876void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2877 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002878
fmalita85d5eb92015-03-04 11:20:12 -08002879 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002880 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002881 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002882 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002883 SkRect tmp;
2884 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2885 return;
2886 }
2887 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002888 }
2889
fmalita024f9962015-03-03 19:08:17 -08002890 // We cannot filter in the looper as we normally do, because the paint is
2891 // incomplete at this point (text-related attributes are embedded within blob run paints).
2892 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002893 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002894
fmalita85d5eb92015-03-04 11:20:12 -08002895 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002896
fmalitaaa1b9122014-08-28 14:32:24 -07002897 while (iter.next()) {
2898 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002899 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002900 }
2901
fmalitaaa1b9122014-08-28 14:32:24 -07002902 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002903
2904 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002905}
2906
reed@google.come0d9ce82014-04-23 04:00:17 +00002907// These will become non-virtual, so they always call the (virtual) onDraw... method
2908void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2909 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002910 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002911 if (byteLength) {
2912 this->onDrawText(text, byteLength, x, y, paint);
2913 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002914}
2915void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2916 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002917 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002918 if (byteLength) {
2919 this->onDrawPosText(text, byteLength, pos, paint);
2920 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002921}
2922void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2923 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002924 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002925 if (byteLength) {
2926 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2927 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002928}
2929void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2930 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002931 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002932 if (byteLength) {
2933 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2934 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002935}
reed45561a02016-07-07 12:47:17 -07002936void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2937 const SkRect* cullRect, const SkPaint& paint) {
2938 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2939 if (byteLength) {
2940 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2941 }
2942}
fmalita00d5c2c2014-08-21 08:53:26 -07002943void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2944 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002945 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002946 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002947 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002948}
reed@google.come0d9ce82014-04-23 04:00:17 +00002949
reed41af9662015-01-05 07:49:08 -08002950void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2951 const SkPoint verts[], const SkPoint texs[],
2952 const SkColor colors[], SkXfermode* xmode,
2953 const uint16_t indices[], int indexCount,
2954 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002955 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002956 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002957
reed@android.com8a1c16f2008-12-17 15:59:43 +00002958 while (iter.next()) {
2959 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002960 colors, xmode, indices, indexCount,
2961 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002962 }
reed@google.com4b226022011-01-11 18:32:13 +00002963
reed@google.com4e2b3d32011-04-07 14:18:59 +00002964 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002965}
2966
dandovb3c9d1c2014-08-12 08:34:29 -07002967void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2968 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002969 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002970 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002971 return;
2972 }
mtklein6cfa73a2014-08-13 13:33:49 -07002973
dandovecfff212014-08-04 10:02:00 -07002974 // Since a patch is always within the convex hull of the control points, we discard it when its
2975 // bounding rectangle is completely outside the current clip.
2976 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002977 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002978 if (this->quickReject(bounds)) {
2979 return;
2980 }
mtklein6cfa73a2014-08-13 13:33:49 -07002981
dandovb3c9d1c2014-08-12 08:34:29 -07002982 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2983}
2984
2985void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2986 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2987
halcanary96fcdcc2015-08-27 07:41:13 -07002988 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002989
dandovecfff212014-08-04 10:02:00 -07002990 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002991 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002992 }
mtklein6cfa73a2014-08-13 13:33:49 -07002993
dandovecfff212014-08-04 10:02:00 -07002994 LOOPER_END
2995}
2996
reeda8db7282015-07-07 10:22:31 -07002997void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002998 RETURN_ON_NULL(dr);
2999 if (x || y) {
3000 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
3001 this->onDrawDrawable(dr, &matrix);
3002 } else {
3003 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08003004 }
3005}
3006
reeda8db7282015-07-07 10:22:31 -07003007void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08003008 RETURN_ON_NULL(dr);
3009 if (matrix && matrix->isIdentity()) {
3010 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07003011 }
reede3b38ce2016-01-08 09:18:44 -08003012 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07003013}
3014
3015void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
3016 SkRect bounds = dr->getBounds();
3017 if (matrix) {
3018 matrix->mapRect(&bounds);
3019 }
3020 if (this->quickReject(bounds)) {
3021 return;
3022 }
3023 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08003024}
3025
reed71c3c762015-06-24 10:29:17 -07003026void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
3027 const SkColor colors[], int count, SkXfermode::Mode mode,
3028 const SkRect* cull, const SkPaint* paint) {
3029 if (cull && this->quickReject(*cull)) {
3030 return;
3031 }
3032
3033 SkPaint pnt;
3034 if (paint) {
3035 pnt = *paint;
3036 }
halcanary9d524f22016-03-29 09:03:52 -07003037
halcanary96fcdcc2015-08-27 07:41:13 -07003038 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07003039 while (iter.next()) {
3040 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
3041 }
3042 LOOPER_END
3043}
3044
reedf70b5312016-03-04 16:36:20 -08003045void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
3046 SkASSERT(key);
3047
3048 SkPaint paint;
3049 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
3050 while (iter.next()) {
3051 iter.fDevice->drawAnnotation(iter, rect, key, value);
3052 }
3053 LOOPER_END
3054}
3055
reed@android.com8a1c16f2008-12-17 15:59:43 +00003056//////////////////////////////////////////////////////////////////////////////
3057// These methods are NOT virtual, and therefore must call back into virtual
3058// methods, rather than actually drawing themselves.
3059//////////////////////////////////////////////////////////////////////////////
3060
3061void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00003062 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003063 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003064 SkPaint paint;
3065
3066 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00003067 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003068 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003069 }
3070 this->drawPaint(paint);
3071}
3072
reed@android.com845fdac2009-06-23 03:01:32 +00003073void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003074 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003075 SkPaint paint;
3076
3077 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00003078 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003079 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003080 }
3081 this->drawPaint(paint);
3082}
3083
3084void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003085 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003086 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00003087
reed@android.com8a1c16f2008-12-17 15:59:43 +00003088 pt.set(x, y);
3089 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3090}
3091
3092void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003093 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003094 SkPoint pt;
3095 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003096
reed@android.com8a1c16f2008-12-17 15:59:43 +00003097 pt.set(x, y);
3098 paint.setColor(color);
3099 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3100}
3101
3102void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3103 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003104 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003105 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003106
reed@android.com8a1c16f2008-12-17 15:59:43 +00003107 pts[0].set(x0, y0);
3108 pts[1].set(x1, y1);
3109 this->drawPoints(kLines_PointMode, 2, pts, paint);
3110}
3111
3112void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3113 SkScalar right, SkScalar bottom,
3114 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003115 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003116 SkRect r;
3117
3118 r.set(left, top, right, bottom);
3119 this->drawRect(r, paint);
3120}
3121
3122void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3123 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003124 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003125 if (radius < 0) {
3126 radius = 0;
3127 }
3128
3129 SkRect r;
3130 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003131 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003132}
3133
3134void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3135 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003136 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003137 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003138 SkRRect rrect;
3139 rrect.setRectXY(r, rx, ry);
3140 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003141 } else {
3142 this->drawRect(r, paint);
3143 }
3144}
3145
reed@android.com8a1c16f2008-12-17 15:59:43 +00003146void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3147 SkScalar sweepAngle, bool useCenter,
3148 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003149 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003150 if (oval.isEmpty() || !sweepAngle) {
3151 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003152 }
bsalomon21af9ca2016-08-25 12:29:23 -07003153 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003154}
3155
3156void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3157 const SkPath& path, SkScalar hOffset,
3158 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003159 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003160 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003161
reed@android.com8a1c16f2008-12-17 15:59:43 +00003162 matrix.setTranslate(hOffset, vOffset);
3163 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3164}
3165
reed@android.comf76bacf2009-05-13 14:00:33 +00003166///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003167
3168/**
3169 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3170 * against the playback cost of recursing into the subpicture to get at its actual ops.
3171 *
3172 * For now we pick a conservatively small value, though measurement (and other heuristics like
3173 * the type of ops contained) may justify changing this value.
3174 */
3175#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003176
reedd5fa1a42014-08-09 11:08:05 -07003177void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003178 RETURN_ON_NULL(picture);
3179
reed1c2c4412015-04-30 13:09:24 -07003180 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003181 if (matrix && matrix->isIdentity()) {
3182 matrix = nullptr;
3183 }
3184 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3185 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3186 picture->playback(this);
3187 } else {
3188 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003189 }
3190}
robertphillips9b14f262014-06-04 05:40:44 -07003191
reedd5fa1a42014-08-09 11:08:05 -07003192void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3193 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003194 if (!paint || paint->canComputeFastBounds()) {
3195 SkRect bounds = picture->cullRect();
3196 if (paint) {
3197 paint->computeFastBounds(bounds, &bounds);
3198 }
3199 if (matrix) {
3200 matrix->mapRect(&bounds);
3201 }
3202 if (this->quickReject(bounds)) {
3203 return;
3204 }
3205 }
3206
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003207 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003208 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003209}
3210
vjiaoblack95302da2016-07-21 10:25:54 -07003211#ifdef SK_EXPERIMENTAL_SHADOWING
3212void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3213 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003214 const SkPaint* paint,
3215 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003216 RETURN_ON_NULL(picture);
3217
3218 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3219
vjiaoblacke6f5d562016-08-25 06:30:23 -07003220 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003221}
3222
3223void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3224 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003225 const SkPaint* paint,
3226 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003227 if (!paint || paint->canComputeFastBounds()) {
3228 SkRect bounds = picture->cullRect();
3229 if (paint) {
3230 paint->computeFastBounds(bounds, &bounds);
3231 }
3232 if (matrix) {
3233 matrix->mapRect(&bounds);
3234 }
3235 if (this->quickReject(bounds)) {
3236 return;
3237 }
3238 }
3239
3240 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3241
vjiaoblacke6f5d562016-08-25 06:30:23 -07003242 sk_sp<SkImage> povDepthMap;
3243 sk_sp<SkImage> diffuseMap;
3244
vjiaoblack904527d2016-08-09 09:32:09 -07003245 // povDepthMap
3246 {
3247 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003248 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3249 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003250 sk_sp<SkLights> povLight = builder.finish();
3251
3252 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3253 picture->cullRect().height(),
3254 kBGRA_8888_SkColorType,
3255 kOpaque_SkAlphaType);
3256
3257 // Create a new surface (that matches the backend of canvas)
3258 // to create the povDepthMap
3259 sk_sp<SkSurface> surf(this->makeSurface(info));
3260
3261 // Wrap another SPFCanvas around the surface
3262 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3263 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3264
3265 // set the depth map canvas to have the light as the user's POV
3266 depthMapCanvas->setLights(std::move(povLight));
3267
3268 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003269 povDepthMap = surf->makeImageSnapshot();
3270 }
3271
3272 // diffuseMap
3273 {
3274 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3275 picture->cullRect().height(),
3276 kBGRA_8888_SkColorType,
3277 kOpaque_SkAlphaType);
3278
3279 sk_sp<SkSurface> surf(this->makeSurface(info));
3280 surf->getCanvas()->drawPicture(picture);
3281
3282 diffuseMap = surf->makeImageSnapshot();
3283 }
vjiaoblack904527d2016-08-09 09:32:09 -07003284
3285 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3286 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003287 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3288 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003289
3290 // TODO: pass the depth to the shader in vertices, or uniforms
3291 // so we don't have to render depth and color separately
3292 for (int i = 0; i < fLights->numLights(); ++i) {
3293 // skip over ambient lights; they don't cast shadows
3294 // lights that have shadow maps do not need updating (because lights are immutable)
3295 sk_sp<SkImage> depthMap;
3296 SkISize shMapSize;
3297
3298 if (fLights->light(i).getShadowMap() != nullptr) {
3299 continue;
3300 }
3301
3302 if (fLights->light(i).isRadial()) {
3303 shMapSize.fHeight = 1;
3304 shMapSize.fWidth = (int) picture->cullRect().width();
3305
3306 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3307 kBGRA_8888_SkColorType,
3308 kOpaque_SkAlphaType);
3309
3310 // Create new surface (that matches the backend of canvas)
3311 // for each shadow map
3312 sk_sp<SkSurface> surf(this->makeSurface(info));
3313
3314 // Wrap another SPFCanvas around the surface
3315 SkCanvas* depthMapCanvas = surf->getCanvas();
3316
3317 SkLights::Builder builder;
3318 builder.add(fLights->light(i));
3319 sk_sp<SkLights> curLight = builder.finish();
3320
3321 sk_sp<SkShader> shadowMapShader;
3322 shadowMapShader = SkRadialShadowMapShader::Make(
3323 povDepthShader, curLight,
3324 (int) picture->cullRect().width(),
3325 (int) picture->cullRect().height());
3326
3327 SkPaint shadowMapPaint;
3328 shadowMapPaint.setShader(std::move(shadowMapShader));
3329
3330 depthMapCanvas->setLights(curLight);
3331
3332 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3333 diffuseMap->height()),
3334 shadowMapPaint);
3335
3336 depthMap = surf->makeImageSnapshot();
3337
3338 } else {
3339 // TODO: compute the correct size of the depth map from the light properties
3340 // TODO: maybe add a kDepth_8_SkColorType
3341 // TODO: find actual max depth of picture
3342 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3343 fLights->light(i), 255,
3344 (int) picture->cullRect().width(),
3345 (int) picture->cullRect().height());
3346
3347 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3348 kBGRA_8888_SkColorType,
3349 kOpaque_SkAlphaType);
3350
3351 // Create a new surface (that matches the backend of canvas)
3352 // for each shadow map
3353 sk_sp<SkSurface> surf(this->makeSurface(info));
3354
3355 // Wrap another SPFCanvas around the surface
3356 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3357 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3358 depthMapCanvas->setShadowParams(params);
3359
3360 // set the depth map canvas to have the light we're drawing.
3361 SkLights::Builder builder;
3362 builder.add(fLights->light(i));
3363 sk_sp<SkLights> curLight = builder.finish();
3364 depthMapCanvas->setLights(std::move(curLight));
3365
3366 depthMapCanvas->drawPicture(picture);
3367 depthMap = surf->makeImageSnapshot();
3368 }
3369
3370 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3371 fLights->light(i).setShadowMap(std::move(depthMap));
3372 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3373 // we blur the variance map
3374 SkPaint blurPaint;
3375 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3376 params.fShadowRadius, nullptr));
3377
3378 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3379 kBGRA_8888_SkColorType,
3380 kOpaque_SkAlphaType);
3381
3382 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3383
3384 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3385
3386 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3387 }
3388 }
3389
3390 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003391 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3392 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003393 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003394 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003395 diffuseMap->height(),
3396 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003397
3398 shadowPaint.setShader(shadowShader);
3399
3400 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003401}
3402#endif
3403
reed@android.com8a1c16f2008-12-17 15:59:43 +00003404///////////////////////////////////////////////////////////////////////////////
3405///////////////////////////////////////////////////////////////////////////////
3406
reed3aafe112016-08-18 12:45:34 -07003407SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003408 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003409
3410 SkASSERT(canvas);
3411
reed3aafe112016-08-18 12:45:34 -07003412 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003413 fDone = !fImpl->next();
3414}
3415
3416SkCanvas::LayerIter::~LayerIter() {
3417 fImpl->~SkDrawIter();
3418}
3419
3420void SkCanvas::LayerIter::next() {
3421 fDone = !fImpl->next();
3422}
3423
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003424SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003425 return fImpl->getDevice();
3426}
3427
3428const SkMatrix& SkCanvas::LayerIter::matrix() const {
3429 return fImpl->getMatrix();
3430}
3431
3432const SkPaint& SkCanvas::LayerIter::paint() const {
3433 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003434 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003435 paint = &fDefaultPaint;
3436 }
3437 return *paint;
3438}
3439
reed1e7f5e72016-04-27 07:49:17 -07003440const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003441int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3442int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003443
3444///////////////////////////////////////////////////////////////////////////////
3445
fmalitac3b589a2014-06-05 12:40:07 -07003446SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003447
3448///////////////////////////////////////////////////////////////////////////////
3449
3450static bool supported_for_raster_canvas(const SkImageInfo& info) {
3451 switch (info.alphaType()) {
3452 case kPremul_SkAlphaType:
3453 case kOpaque_SkAlphaType:
3454 break;
3455 default:
3456 return false;
3457 }
3458
3459 switch (info.colorType()) {
3460 case kAlpha_8_SkColorType:
3461 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003462 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003463 break;
3464 default:
3465 return false;
3466 }
3467
3468 return true;
3469}
3470
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003471SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3472 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003473 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003474 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003475
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003476 SkBitmap bitmap;
3477 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003478 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003479 }
halcanary385fe4d2015-08-26 13:07:48 -07003480 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003481}
reedd5fa1a42014-08-09 11:08:05 -07003482
3483///////////////////////////////////////////////////////////////////////////////
3484
3485SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003486 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003487 : fCanvas(canvas)
3488 , fSaveCount(canvas->getSaveCount())
3489{
bsalomon49f085d2014-09-05 13:34:00 -07003490 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003491 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003492 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003493 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003494 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003495 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003496 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003497 canvas->save();
3498 }
mtklein6cfa73a2014-08-13 13:33:49 -07003499
bsalomon49f085d2014-09-05 13:34:00 -07003500 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003501 canvas->concat(*matrix);
3502 }
3503}
3504
3505SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3506 fCanvas->restoreToCount(fSaveCount);
3507}
reede8f30622016-03-23 18:59:25 -07003508
3509#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3510SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
3511 return this->makeSurface(info, props).release();
3512}
3513#endif