blob: 7597c7a07a7ec4a62c3484d5aad00e9828fbd756 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
bungemand3ebb482015-08-05 13:57:49 -07008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080017#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
msarettfbfa2582016-08-12 08:29:08 -070025#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070026#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070027#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000028#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070029#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000030#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080031#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000032#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070033#include "SkShadowPaintFilterCanvas.h"
34#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000035#include "SkSmallAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080036#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000037#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070038#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000039#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000040#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080041#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070042#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080045#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000046#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070047#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070048
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000049#endif
50
reede3b38ce2016-01-08 09:18:44 -080051#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
52
reedc83a2972015-07-16 07:40:45 -070053/*
54 * Return true if the drawing this rect would hit every pixels in the canvas.
55 *
56 * Returns false if
57 * - rect does not contain the canvas' bounds
58 * - paint is not fill
59 * - paint would blur or otherwise change the coverage of the rect
60 */
61bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
62 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070063 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
64 (int)kNone_ShaderOverrideOpacity,
65 "need_matching_enums0");
66 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
67 (int)kOpaque_ShaderOverrideOpacity,
68 "need_matching_enums1");
69 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
70 (int)kNotOpaque_ShaderOverrideOpacity,
71 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070072
73 const SkISize size = this->getBaseLayerSize();
74 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
75 if (!this->getClipStack()->quickContains(bounds)) {
76 return false;
77 }
78
79 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070080 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070081 return false; // conservative
82 }
halcanaryc5769b22016-08-10 07:13:21 -070083
84 SkRect devRect;
85 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
86 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070087 return false;
88 }
89 }
90
91 if (paint) {
92 SkPaint::Style paintStyle = paint->getStyle();
93 if (!(paintStyle == SkPaint::kFill_Style ||
94 paintStyle == SkPaint::kStrokeAndFill_Style)) {
95 return false;
96 }
97 if (paint->getMaskFilter() || paint->getLooper()
98 || paint->getPathEffect() || paint->getImageFilter()) {
99 return false; // conservative
100 }
101 }
102 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
103}
104
105///////////////////////////////////////////////////////////////////////////////////////////////////
106
reedd990e2f2014-12-22 11:58:30 -0800107static bool gIgnoreSaveLayerBounds;
108void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
109 gIgnoreSaveLayerBounds = ignore;
110}
111bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
112 return gIgnoreSaveLayerBounds;
113}
114
reed0acf1b42014-12-22 16:12:38 -0800115static bool gTreatSpriteAsBitmap;
116void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
117 gTreatSpriteAsBitmap = spriteAsBitmap;
118}
119bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
120 return gTreatSpriteAsBitmap;
121}
122
reed@google.comda17f752012-08-16 18:27:05 +0000123// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124//#define SK_TRACE_SAVERESTORE
125
126#ifdef SK_TRACE_SAVERESTORE
127 static int gLayerCounter;
128 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
129 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
130
131 static int gRecCounter;
132 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
133 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
134
135 static int gCanvasCounter;
136 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
137 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
138#else
139 #define inc_layer()
140 #define dec_layer()
141 #define inc_rec()
142 #define dec_rec()
143 #define inc_canvas()
144 #define dec_canvas()
145#endif
146
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000147typedef SkTLazy<SkPaint> SkLazyPaint;
148
reedc83a2972015-07-16 07:40:45 -0700149void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000150 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700151 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
152 ? SkSurface::kDiscard_ContentChangeMode
153 : SkSurface::kRetain_ContentChangeMode);
154 }
155}
156
157void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
158 ShaderOverrideOpacity overrideOpacity) {
159 if (fSurfaceBase) {
160 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
161 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
162 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
163 // and therefore we don't care which mode we're in.
164 //
165 if (fSurfaceBase->outstandingImageSnapshot()) {
166 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
167 mode = SkSurface::kDiscard_ContentChangeMode;
168 }
169 }
170 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000171 }
172}
173
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000176/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 The clip/matrix/proc are fields that reflect the top of the save/restore
178 stack. Whenever the canvas changes, it marks a dirty flag, and then before
179 these are used (assuming we're not on a layer) we rebuild these cache
180 values: they reflect the top of the save stack, but translated and clipped
181 by the device's XY offset and bitmap-bounds.
182*/
183struct DeviceCM {
184 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000185 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000186 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000187 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700188 const SkMatrix* fMatrix;
189 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700190 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191
reed96e657d2015-03-10 17:30:07 -0700192 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700193 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700194 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700195 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700196 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700197 {
reed2c9e2002016-07-25 08:05:22 -0700198 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000199 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700200 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000201 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000203 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700204 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700205 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000206 }
reed@google.com4b226022011-01-11 18:32:13 +0000207
mtkleinfeaadee2015-04-08 11:25:48 -0700208 void reset(const SkIRect& bounds) {
209 SkASSERT(!fPaint);
210 SkASSERT(!fNext);
211 SkASSERT(fDevice);
212 fClip.setRect(bounds);
213 }
214
reed@google.com045e62d2011-10-24 12:19:46 +0000215 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700216 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000217 int x = fDevice->getOrigin().x();
218 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 int width = fDevice->width();
220 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000221
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 if ((x | y) == 0) {
223 fMatrix = &totalMatrix;
224 fClip = totalClip;
225 } else {
226 fMatrixStorage = totalMatrix;
227 fMatrixStorage.postTranslate(SkIntToScalar(-x),
228 SkIntToScalar(-y));
229 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000230
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 totalClip.translate(-x, -y, &fClip);
232 }
233
reed@google.com045e62d2011-10-24 12:19:46 +0000234 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235
236 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000239 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 SkRegion::kDifference_Op);
241 }
reed@google.com4b226022011-01-11 18:32:13 +0000242
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243#ifdef SK_DEBUG
244 if (!fClip.isEmpty()) {
245 SkIRect deviceR;
246 deviceR.set(0, 0, width, height);
247 SkASSERT(deviceR.contains(fClip.getBounds()));
248 }
249#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000250 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251};
252
253/* This is the record we keep for each save/restore level in the stack.
254 Since a level optionally copies the matrix and/or stack, we have pointers
255 for these fields. If the value is copied for this level, the copy is
256 stored in the ...Storage field, and the pointer points to that. If the
257 value is not copied for this level, we ignore ...Storage, and just point
258 at the corresponding value in the previous level in the stack.
259*/
260class SkCanvas::MCRec {
261public:
reed1f836ee2014-07-07 07:49:34 -0700262 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700263 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 /* If there are any layers in the stack, this points to the top-most
265 one that is at or below this level in the stack (so we know what
266 bitmap/device to draw into from this level. This value is NOT
267 reference counted, since the real owner is either our fLayer field,
268 or a previous one in a lower level.)
269 */
reed2ff1fce2014-12-11 07:07:37 -0800270 DeviceCM* fTopLayer;
271 SkRasterClip fRasterClip;
272 SkMatrix fMatrix;
273 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274
vjiaoblacke5de1302016-07-13 14:05:28 -0700275 // This is the current cumulative depth (aggregate of all done translateZ calls)
276 SkScalar fCurDrawDepth;
277
reedd9544982014-09-09 18:46:22 -0700278 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700279 fFilter = nullptr;
280 fLayer = nullptr;
281 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800282 fMatrix.reset();
283 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700284 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700285
reedd9544982014-09-09 18:46:22 -0700286 // don't bother initializing fNext
287 inc_rec();
288 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700289 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
290 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700291 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700292 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700293 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800294 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700295
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 // don't bother initializing fNext
297 inc_rec();
298 }
299 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000300 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700301 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302 dec_rec();
303 }
mtkleinfeaadee2015-04-08 11:25:48 -0700304
305 void reset(const SkIRect& bounds) {
306 SkASSERT(fLayer);
307 SkASSERT(fDeferredSaveCount == 0);
308
309 fMatrix.reset();
310 fRasterClip.setRect(bounds);
311 fLayer->reset(bounds);
312 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313};
314
reed02f9ed72016-09-06 09:06:18 -0700315static SkIRect compute_device_bounds(SkBaseDevice* device) {
316 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
317 device->width(), device->height());
318}
319
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320class SkDrawIter : public SkDraw {
321public:
reed3aafe112016-08-18 12:45:34 -0700322 SkDrawIter(SkCanvas* canvas) {
junov@google.com4370aed2012-01-18 16:21:08 +0000323 canvas = canvas->canvasForDrawIter();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324 canvas->updateDeviceCMCache();
325
reed687fa1c2015-04-07 08:00:56 -0700326 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700328
329 fMultiDeviceCS = nullptr;
330 if (fCurrLayer->fNext) {
331 fMultiDeviceCS = canvas->fClipStack;
332 fMultiDeviceCS->save();
333 }
334 }
335
336 ~SkDrawIter() {
337 if (fMultiDeviceCS) {
338 fMultiDeviceCS->restore();
339 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 }
reed@google.com4b226022011-01-11 18:32:13 +0000341
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700343 if (fMultiDeviceCS && fDevice) {
344 // remove the previous device's bounds
reed73603f32016-09-20 08:42:38 -0700345 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), SkCanvas::kDifference_Op);
reed02f9ed72016-09-06 09:06:18 -0700346 }
347
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700349 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
350 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 }
352
reed@google.comf68c5e22012-02-24 16:38:58 +0000353 const DeviceCM* rec = fCurrLayer;
354 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355
356 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000357 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700359 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700360 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700361 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000363 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364
365 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700366 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000367
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368 return true;
369 }
370 return false;
371 }
reed@google.com4b226022011-01-11 18:32:13 +0000372
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000373 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700374 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000375 int getX() const { return fDevice->getOrigin().x(); }
376 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000379
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381 const DeviceCM* fCurrLayer;
382 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700383 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384
385 typedef SkDraw INHERITED;
386};
387
388/////////////////////////////////////////////////////////////////////////////
389
reeddbc3cef2015-04-29 12:18:57 -0700390static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
391 return lazy->isValid() ? lazy->get() : lazy->set(orig);
392}
393
394/**
395 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700396 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700397 */
reedd053ce92016-03-22 10:17:23 -0700398static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700399 SkImageFilter* imgf = paint.getImageFilter();
400 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700401 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700402 }
403
reedd053ce92016-03-22 10:17:23 -0700404 SkColorFilter* imgCFPtr;
405 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700406 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700407 }
reedd053ce92016-03-22 10:17:23 -0700408 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700409
410 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700411 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700412 // there is no existing paint colorfilter, so we can just return the imagefilter's
413 return imgCF;
414 }
415
416 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
417 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700418 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700419}
420
senorblanco87e066e2015-10-28 11:23:36 -0700421/**
422 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
423 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
424 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
425 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
426 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
427 * conservative "effective" bounds based on the settings in the paint... with one exception. This
428 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
429 * deliberately ignored.
430 */
431static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
432 const SkRect& rawBounds,
433 SkRect* storage) {
434 SkPaint tmpUnfiltered(paint);
435 tmpUnfiltered.setImageFilter(nullptr);
436 if (tmpUnfiltered.canComputeFastBounds()) {
437 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
438 } else {
439 return rawBounds;
440 }
441}
442
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443class AutoDrawLooper {
444public:
senorblanco87e066e2015-10-28 11:23:36 -0700445 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
446 // paint. It's used to determine the size of the offscreen layer for filters.
447 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700448 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700449 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000450 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800451#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800453#else
454 fFilter = nullptr;
455#endif
reed4a8126e2014-09-22 07:29:03 -0700456 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000457 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700458 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000459 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460
reedd053ce92016-03-22 10:17:23 -0700461 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700462 if (simplifiedCF) {
463 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700464 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700465 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700466 fPaint = paint;
467 }
468
469 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700470 /**
471 * We implement ImageFilters for a given draw by creating a layer, then applying the
472 * imagefilter to the pixels of that layer (its backing surface/image), and then
473 * we call restore() to xfer that layer to the main canvas.
474 *
475 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
476 * 2. Generate the src pixels:
477 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
478 * return (fPaint). We then draw the primitive (using srcover) into a cleared
479 * buffer/surface.
480 * 3. Restore the layer created in #1
481 * The imagefilter is passed the buffer/surface from the layer (now filled with the
482 * src pixels of the primitive). It returns a new "filtered" buffer, which we
483 * draw onto the previous layer using the xfermode from the original paint.
484 */
reed@google.com8926b162012-03-23 15:36:36 +0000485 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700486 tmp.setImageFilter(fPaint->getImageFilter());
reedcfb6bdf2016-03-29 11:32:50 -0700487 tmp.setXfermode(sk_ref_sp(fPaint->getXfermode()));
senorblanco87e066e2015-10-28 11:23:36 -0700488 SkRect storage;
489 if (rawBounds) {
490 // Make rawBounds include all paint outsets except for those due to image filters.
491 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
492 }
reedbfd5f172016-01-07 11:28:08 -0800493 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700494 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700495 fTempLayerForImageFilter = true;
496 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000497 }
498
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000499 if (SkDrawLooper* looper = paint.getLooper()) {
500 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
501 looper->contextSize());
502 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000503 fIsSimple = false;
504 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700505 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000506 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700507 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000508 }
509 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000510
reed@android.com8a1c16f2008-12-17 15:59:43 +0000511 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700512 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000513 fCanvas->internalRestore();
514 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000515 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000517
reed@google.com4e2b3d32011-04-07 14:18:59 +0000518 const SkPaint& paint() const {
519 SkASSERT(fPaint);
520 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000522
reed@google.com129ec222012-05-15 13:24:09 +0000523 bool next(SkDrawFilter::Type drawType) {
524 if (fDone) {
525 return false;
526 } else if (fIsSimple) {
527 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000528 return !fPaint->nothingToDraw();
529 } else {
530 return this->doNext(drawType);
531 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000532 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000533
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534private:
reeddbc3cef2015-04-29 12:18:57 -0700535 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
536 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000537 SkCanvas* fCanvas;
538 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000539 SkDrawFilter* fFilter;
540 const SkPaint* fPaint;
541 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700542 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000543 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000544 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000545 SkDrawLooper::Context* fLooperContext;
546 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000547
548 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549};
550
reed@google.com129ec222012-05-15 13:24:09 +0000551bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700552 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000553 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700554 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000555
reeddbc3cef2015-04-29 12:18:57 -0700556 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
557 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000558
reed5c476fb2015-04-20 08:04:21 -0700559 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700560 paint->setImageFilter(nullptr);
561 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000562 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000563
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000564 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000565 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000566 return false;
567 }
568 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000569 if (!fFilter->filter(paint, drawType)) {
570 fDone = true;
571 return false;
572 }
halcanary96fcdcc2015-08-27 07:41:13 -0700573 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000574 // no looper means we only draw once
575 fDone = true;
576 }
577 }
578 fPaint = paint;
579
580 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000581 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000582 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000583 }
584
585 // call this after any possible paint modifiers
586 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700587 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000588 return false;
589 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000590 return true;
591}
592
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593////////// macros to place around the internal draw calls //////////////////
594
reed3aafe112016-08-18 12:45:34 -0700595#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
596 this->predrawNotify(); \
597 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
598 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800599 SkDrawIter iter(this);
600
601
reed@google.com8926b162012-03-23 15:36:36 +0000602#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000603 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700604 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000605 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000606 SkDrawIter iter(this);
607
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000608#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000609 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700610 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000611 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000613
reedc83a2972015-07-16 07:40:45 -0700614#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
615 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700616 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700617 while (looper.next(type)) { \
618 SkDrawIter iter(this);
619
reed@google.com4e2b3d32011-04-07 14:18:59 +0000620#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000621
622////////////////////////////////////////////////////////////////////////////
623
msarettfbfa2582016-08-12 08:29:08 -0700624static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
625 if (bounds.isEmpty()) {
626 return SkRect::MakeEmpty();
627 }
628
629 // Expand bounds out by 1 in case we are anti-aliasing. We store the
630 // bounds as floats to enable a faster quick reject implementation.
631 SkRect dst;
632 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
633 return dst;
634}
635
mtkleinfeaadee2015-04-08 11:25:48 -0700636void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
637 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700638 fClipStack->reset();
639 fMCRec->reset(bounds);
640
641 // We're peering through a lot of structs here. Only at this scope do we
642 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
643 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700644 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700645 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700646}
647
reedd9544982014-09-09 18:46:22 -0700648SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800649 if (device && device->forceConservativeRasterClip()) {
650 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
651 }
652 // Since init() is only called once by our constructors, it is safe to perform this
653 // const-cast.
654 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
655
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000656 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700657 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800658 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700659 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700660#ifdef SK_EXPERIMENTAL_SHADOWING
661 fLights = nullptr;
662#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663
halcanary385fe4d2015-08-26 13:07:48 -0700664 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700665
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700667 new (fMCRec) MCRec(fConservativeRasterClip);
msarett9637ea92016-08-18 14:03:30 -0700668 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669
reeda499f902015-05-01 09:34:31 -0700670 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
671 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700672 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700673 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700674
reed@android.com8a1c16f2008-12-17 15:59:43 +0000675 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000676
halcanary96fcdcc2015-08-27 07:41:13 -0700677 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000678
reedf92c8662014-08-18 08:02:43 -0700679 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700680 // The root device and the canvas should always have the same pixel geometry
681 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700682 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800683 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700684 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700685 }
msarettfbfa2582016-08-12 08:29:08 -0700686
reedf92c8662014-08-18 08:02:43 -0700687 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000688}
689
reed@google.comcde92112011-07-06 20:00:52 +0000690SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000691 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700692 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800693 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000694{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000695 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000696
halcanary96fcdcc2015-08-27 07:41:13 -0700697 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000698}
699
reedd9544982014-09-09 18:46:22 -0700700static SkBitmap make_nopixels(int width, int height) {
701 SkBitmap bitmap;
702 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
703 return bitmap;
704}
705
706class SkNoPixelsBitmapDevice : public SkBitmapDevice {
707public:
robertphillipsfcf78292015-06-19 11:49:52 -0700708 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
709 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800710 {
711 this->setOrigin(bounds.x(), bounds.y());
712 }
reedd9544982014-09-09 18:46:22 -0700713
714private:
piotaixrb5fae932014-09-24 13:03:30 -0700715
reedd9544982014-09-09 18:46:22 -0700716 typedef SkBitmapDevice INHERITED;
717};
718
reed96a857e2015-01-25 10:33:58 -0800719SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000720 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800721 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800722 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000723{
724 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700725
halcanary385fe4d2015-08-26 13:07:48 -0700726 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
727 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700728}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000729
reed78e27682014-11-19 08:04:34 -0800730SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700731 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700732 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800733 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700734{
735 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700736
halcanary385fe4d2015-08-26 13:07:48 -0700737 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700738}
739
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000740SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000741 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700742 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800743 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000744{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000745 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700746
reedd9544982014-09-09 18:46:22 -0700747 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000748}
749
robertphillipsfcf78292015-06-19 11:49:52 -0700750SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
751 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700752 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800753 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700754{
755 inc_canvas();
756
757 this->init(device, flags);
758}
759
reed4a8126e2014-09-22 07:29:03 -0700760SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700761 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700762 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800763 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700764{
765 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700766
halcanary385fe4d2015-08-26 13:07:48 -0700767 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700768 this->init(device, kDefault_InitFlags);
769}
reed29c857d2014-09-21 10:25:07 -0700770
reed4a8126e2014-09-22 07:29:03 -0700771SkCanvas::SkCanvas(const SkBitmap& bitmap)
772 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
773 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800774 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700775{
776 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700777
halcanary385fe4d2015-08-26 13:07:48 -0700778 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700779 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000780}
781
782SkCanvas::~SkCanvas() {
783 // free up the contents of our deque
784 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000785
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786 this->internalRestore(); // restore the last, since we're going away
787
halcanary385fe4d2015-08-26 13:07:48 -0700788 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000789
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790 dec_canvas();
791}
792
fmalita53d9f1c2016-01-25 06:23:54 -0800793#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794SkDrawFilter* SkCanvas::getDrawFilter() const {
795 return fMCRec->fFilter;
796}
797
798SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700799 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000800 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
801 return filter;
802}
fmalita77650002016-01-21 18:47:11 -0800803#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000805SkMetaData& SkCanvas::getMetaData() {
806 // metadata users are rare, so we lazily allocate it. If that changes we
807 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700808 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000809 fMetaData = new SkMetaData;
810 }
811 return *fMetaData;
812}
813
reed@android.com8a1c16f2008-12-17 15:59:43 +0000814///////////////////////////////////////////////////////////////////////////////
815
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000816void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700817 this->onFlush();
818}
819
820void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000821 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000822 if (device) {
823 device->flush();
824 }
825}
826
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000827SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000828 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000829 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
830}
831
senorblancoafc7cce2016-02-02 18:44:15 -0800832SkIRect SkCanvas::getTopLayerBounds() const {
833 SkBaseDevice* d = this->getTopDevice();
834 if (!d) {
835 return SkIRect::MakeEmpty();
836 }
837 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
838}
839
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000840SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000842 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000843 SkASSERT(rec && rec->fLayer);
844 return rec->fLayer->fDevice;
845}
846
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000847SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000848 if (updateMatrixClip) {
849 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
850 }
reed@google.com9266fed2011-03-30 00:18:03 +0000851 return fMCRec->fTopLayer->fDevice;
852}
853
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000854bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700855 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000856 return false;
857 }
858
859 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700860 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700861 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000862 return false;
863 }
864 weAllocated = true;
865 }
866
reedcf01e312015-05-23 19:14:51 -0700867 SkAutoPixmapUnlock unlocker;
868 if (bitmap->requestLock(&unlocker)) {
869 const SkPixmap& pm = unlocker.pixmap();
870 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
871 return true;
872 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000873 }
874
875 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700876 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000877 }
878 return false;
879}
reed@google.com51df9e32010-12-23 19:29:18 +0000880
bsalomon@google.comc6980972011-11-02 19:57:21 +0000881bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000882 SkIRect r = srcRect;
883 const SkISize size = this->getBaseLayerSize();
884 if (!r.intersect(0, 0, size.width(), size.height())) {
885 bitmap->reset();
886 return false;
887 }
888
reed84825042014-09-02 12:50:45 -0700889 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000890 // bitmap will already be reset.
891 return false;
892 }
893 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
894 bitmap->reset();
895 return false;
896 }
897 return true;
898}
899
reed96472de2014-12-10 09:53:42 -0800900bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000901 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000902 if (!device) {
903 return false;
904 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000905 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800906
reed96472de2014-12-10 09:53:42 -0800907 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
908 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000909 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000910 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000911
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000912 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800913 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000914}
915
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000916bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700917 SkAutoPixmapUnlock unlocker;
918 if (bitmap.requestLock(&unlocker)) {
919 const SkPixmap& pm = unlocker.pixmap();
920 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000921 }
922 return false;
923}
924
925bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
926 int x, int y) {
927 switch (origInfo.colorType()) {
928 case kUnknown_SkColorType:
929 case kIndex_8_SkColorType:
930 return false;
931 default:
932 break;
933 }
halcanary96fcdcc2015-08-27 07:41:13 -0700934 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000935 return false;
936 }
937
938 const SkISize size = this->getBaseLayerSize();
939 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
940 if (!target.intersect(0, 0, size.width(), size.height())) {
941 return false;
942 }
943
944 SkBaseDevice* device = this->getDevice();
945 if (!device) {
946 return false;
947 }
948
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000949 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700950 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000951
952 // if x or y are negative, then we have to adjust pixels
953 if (x > 0) {
954 x = 0;
955 }
956 if (y > 0) {
957 y = 0;
958 }
959 // here x,y are either 0 or negative
960 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
961
reed4af35f32014-06-27 17:47:49 -0700962 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700963 const bool completeOverwrite = info.dimensions() == size;
964 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700965
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000966 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000967 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000968}
reed@google.com51df9e32010-12-23 19:29:18 +0000969
junov@google.com4370aed2012-01-18 16:21:08 +0000970SkCanvas* SkCanvas::canvasForDrawIter() {
971 return this;
972}
973
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974//////////////////////////////////////////////////////////////////////////////
975
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976void SkCanvas::updateDeviceCMCache() {
977 if (fDeviceCMDirty) {
978 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700979 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000981
halcanary96fcdcc2015-08-27 07:41:13 -0700982 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700983 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000985 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986 do {
reedde6c5312016-09-02 12:10:07 -0700987 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700988 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989 }
990 fDeviceCMDirty = false;
991 }
992}
993
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994///////////////////////////////////////////////////////////////////////////////
995
reed2ff1fce2014-12-11 07:07:37 -0800996void SkCanvas::checkForDeferredSave() {
997 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800998 this->doSave();
999 }
1000}
1001
reedf0090cb2014-11-26 08:55:51 -08001002int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -08001003#ifdef SK_DEBUG
1004 int count = 0;
1005 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1006 for (;;) {
1007 const MCRec* rec = (const MCRec*)iter.next();
1008 if (!rec) {
1009 break;
1010 }
1011 count += 1 + rec->fDeferredSaveCount;
1012 }
1013 SkASSERT(count == fSaveCount);
1014#endif
1015 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001016}
1017
1018int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001019 fSaveCount += 1;
1020 fMCRec->fDeferredSaveCount += 1;
1021 return this->getSaveCount() - 1; // return our prev value
1022}
1023
1024void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001025 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001026
1027 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1028 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001029 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001030}
1031
1032void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001033 if (fMCRec->fDeferredSaveCount > 0) {
1034 SkASSERT(fSaveCount > 1);
1035 fSaveCount -= 1;
1036 fMCRec->fDeferredSaveCount -= 1;
1037 } else {
1038 // check for underflow
1039 if (fMCStack.count() > 1) {
1040 this->willRestore();
1041 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001042 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001043 this->internalRestore();
1044 this->didRestore();
1045 }
reedf0090cb2014-11-26 08:55:51 -08001046 }
1047}
1048
1049void SkCanvas::restoreToCount(int count) {
1050 // sanity check
1051 if (count < 1) {
1052 count = 1;
1053 }
mtkleinf0f14112014-12-12 08:46:25 -08001054
reedf0090cb2014-11-26 08:55:51 -08001055 int n = this->getSaveCount() - count;
1056 for (int i = 0; i < n; ++i) {
1057 this->restore();
1058 }
1059}
1060
reed2ff1fce2014-12-11 07:07:37 -08001061void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001063 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001065
reed687fa1c2015-04-07 08:00:56 -07001066 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067}
1068
reed4960eee2015-12-18 07:09:18 -08001069bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001070 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001071}
1072
reed4960eee2015-12-18 07:09:18 -08001073bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001074 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001075 SkIRect clipBounds;
1076 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001077 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001078 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001079
reed96e657d2015-03-10 17:30:07 -07001080 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1081
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001082 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001083 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001084 if (bounds && !imageFilter->canComputeFastBounds()) {
1085 bounds = nullptr;
1086 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001087 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001088 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001089 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001091
reed96e657d2015-03-10 17:30:07 -07001092 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093 r.roundOut(&ir);
1094 // early exit if the layer's bounds are clipped out
1095 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001096 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001097 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001098 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001099 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001100 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101 }
1102 } else { // no user bounds, so just use the clip
1103 ir = clipBounds;
1104 }
reed180aec42015-03-11 10:39:04 -07001105 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106
reed4960eee2015-12-18 07:09:18 -08001107 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001108 // Simplify the current clips since they will be applied properly during restore()
reed73603f32016-09-20 08:42:38 -07001109 fClipStack->clipDevRect(ir, kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001110 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001111 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001112 }
1113
1114 if (intersection) {
1115 *intersection = ir;
1116 }
1117 return true;
1118}
1119
reed4960eee2015-12-18 07:09:18 -08001120
reed4960eee2015-12-18 07:09:18 -08001121int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1122 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001123}
1124
reed70ee31b2015-12-10 13:44:45 -08001125int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001126 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1127}
1128
1129int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1130 SaveLayerRec rec(origRec);
1131 if (gIgnoreSaveLayerBounds) {
1132 rec.fBounds = nullptr;
1133 }
1134 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1135 fSaveCount += 1;
1136 this->internalSaveLayer(rec, strategy);
1137 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001138}
1139
reeda2217ef2016-07-20 06:04:34 -07001140void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1141 SkBaseDevice* dst, const SkMatrix& ctm,
1142 const SkClipStack* clipStack) {
1143 SkDraw draw;
1144 SkRasterClip rc;
1145 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1146 if (!dst->accessPixels(&draw.fDst)) {
1147 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001148 }
reeda2217ef2016-07-20 06:04:34 -07001149 draw.fMatrix = &SkMatrix::I();
1150 draw.fRC = &rc;
1151 draw.fClipStack = clipStack;
1152 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001153
1154 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001155 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001156
1157 int x = src->getOrigin().x() - dst->getOrigin().x();
1158 int y = src->getOrigin().y() - dst->getOrigin().y();
1159 auto special = src->snapSpecial();
1160 if (special) {
1161 dst->drawSpecial(draw, special.get(), x, y, p);
1162 }
robertphillips7354a4b2015-12-16 05:08:27 -08001163}
reed70ee31b2015-12-10 13:44:45 -08001164
reed129ed1c2016-02-22 06:42:31 -08001165static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1166 const SkPaint* paint) {
1167 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1168 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001169 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001170 const bool hasImageFilter = paint && paint->getImageFilter();
1171
1172 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1173 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1174 // force to L32
1175 return SkImageInfo::MakeN32(w, h, alphaType);
1176 } else {
1177 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001178 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001179 }
1180}
1181
reed4960eee2015-12-18 07:09:18 -08001182void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1183 const SkRect* bounds = rec.fBounds;
1184 const SkPaint* paint = rec.fPaint;
1185 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1186
reed8c30a812016-04-20 16:36:51 -07001187 SkLazyPaint lazyP;
1188 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1189 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001190 SkMatrix remainder;
1191 SkSize scale;
1192 /*
1193 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1194 * but they do handle scaling. To accommodate this, we do the following:
1195 *
1196 * 1. Stash off the current CTM
1197 * 2. Decompose the CTM into SCALE and REMAINDER
1198 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1199 * contains the REMAINDER
1200 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1201 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1202 * of the original imagefilter, and draw that (via drawSprite)
1203 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1204 *
1205 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1206 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1207 */
reed96a04f32016-04-25 09:25:15 -07001208 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001209 stashedMatrix.decomposeScale(&scale, &remainder))
1210 {
1211 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1212 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1213 SkPaint* p = lazyP.set(*paint);
1214 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1215 SkFilterQuality::kLow_SkFilterQuality,
1216 sk_ref_sp(imageFilter)));
1217 imageFilter = p->getImageFilter();
1218 paint = p;
1219 }
reed8c30a812016-04-20 16:36:51 -07001220
junov@chromium.orga907ac32012-02-24 21:54:07 +00001221 // do this before we create the layer. We don't call the public save() since
1222 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001223 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001224
1225 fDeviceCMDirty = true;
1226
1227 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001228 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001229 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230 }
1231
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001232 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1233 // the clipRectBounds() call above?
1234 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001235 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001236 }
1237
reed4960eee2015-12-18 07:09:18 -08001238 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001239 SkPixelGeometry geo = fProps.pixelGeometry();
1240 if (paint) {
reed76033be2015-03-14 10:54:31 -07001241 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001242 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001243 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001244 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001245 }
1246 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247
robertphillips5139e502016-07-19 05:10:40 -07001248 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001249 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001250 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001251 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001252 }
reedb2db8982014-11-13 12:41:02 -08001253
robertphillips5139e502016-07-19 05:10:40 -07001254 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001255 paint);
1256
robertphillips5139e502016-07-19 05:10:40 -07001257 SkAutoTUnref<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001258 {
reed70ee31b2015-12-10 13:44:45 -08001259 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001260 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001261 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001262 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
reedcd4051e2016-07-15 09:41:26 -07001263 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001264 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1265 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001266 SkErrorInternals::SetError(kInternalError_SkError,
1267 "Unable to create device for layer.");
1268 return;
reed61f501f2015-04-29 08:34:00 -07001269 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001270 }
robertphillips5139e502016-07-19 05:10:40 -07001271 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001272
robertphillips5139e502016-07-19 05:10:40 -07001273 DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274
1275 layer->fNext = fMCRec->fTopLayer;
1276 fMCRec->fLayer = layer;
1277 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001278
1279 if (rec.fBackdrop) {
1280 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice,
1281 fMCRec->fMatrix, this->getClipStack());
1282 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283}
1284
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001285int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001286 if (0xFF == alpha) {
1287 return this->saveLayer(bounds, nullptr);
1288 } else {
1289 SkPaint tmpPaint;
1290 tmpPaint.setAlpha(alpha);
1291 return this->saveLayer(bounds, &tmpPaint);
1292 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001293}
1294
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295void SkCanvas::internalRestore() {
1296 SkASSERT(fMCStack.count() != 0);
1297
1298 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299
reed687fa1c2015-04-07 08:00:56 -07001300 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001301
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001302 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303 DeviceCM* layer = fMCRec->fLayer; // may be null
1304 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001305 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306
1307 // now do the normal restore()
1308 fMCRec->~MCRec(); // balanced in save()
1309 fMCStack.pop_back();
1310 fMCRec = (MCRec*)fMCStack.back();
1311
1312 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1313 since if we're being recorded, we don't want to record this (the
1314 recorder will have already recorded the restore).
1315 */
bsalomon49f085d2014-09-05 13:34:00 -07001316 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001318 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001319 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001320 // restore what we smashed in internalSaveLayer
1321 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001322 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001324 delete layer;
reedb679ca82015-04-07 04:40:48 -07001325 } else {
1326 // we're at the root
reeda499f902015-05-01 09:34:31 -07001327 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001328 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001329 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001330 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001331 }
msarettfbfa2582016-08-12 08:29:08 -07001332
1333 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001334 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001335 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1336 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337}
1338
reede8f30622016-03-23 18:59:25 -07001339sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001340 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001341 props = &fProps;
1342 }
1343 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001344}
1345
reede8f30622016-03-23 18:59:25 -07001346sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001347 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001348 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001349}
1350
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001351SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001352 return this->onImageInfo();
1353}
1354
1355SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001356 SkBaseDevice* dev = this->getDevice();
1357 if (dev) {
1358 return dev->imageInfo();
1359 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001360 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001361 }
1362}
1363
brianosman898235c2016-04-06 07:38:23 -07001364bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001365 return this->onGetProps(props);
1366}
1367
1368bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001369 SkBaseDevice* dev = this->getDevice();
1370 if (dev) {
1371 if (props) {
1372 *props = fProps;
1373 }
1374 return true;
1375 } else {
1376 return false;
1377 }
1378}
1379
reed6ceeebd2016-03-09 14:26:26 -08001380#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001381const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001382 SkPixmap pmap;
reed6ceeebd2016-03-09 14:26:26 -08001383 if (this->peekPixels(&pmap)) {
1384 if (info) {
1385 *info = pmap.info();
1386 }
1387 if (rowBytes) {
1388 *rowBytes = pmap.rowBytes();
1389 }
1390 return pmap.addr();
reed884e97c2015-05-26 11:31:54 -07001391 }
reed6ceeebd2016-03-09 14:26:26 -08001392 return nullptr;
1393}
1394#endif
1395
1396bool SkCanvas::peekPixels(SkPixmap* pmap) {
1397 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001398}
1399
reed884e97c2015-05-26 11:31:54 -07001400bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001401 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001402 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001403}
1404
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001405void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001406 SkPixmap pmap;
1407 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001408 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001409 }
1410 if (info) {
1411 *info = pmap.info();
1412 }
1413 if (rowBytes) {
1414 *rowBytes = pmap.rowBytes();
1415 }
1416 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001417 *origin = this->getTopDevice(false)->getOrigin();
1418 }
reed884e97c2015-05-26 11:31:54 -07001419 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001420}
1421
reed884e97c2015-05-26 11:31:54 -07001422bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001423 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001424 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001425}
1426
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428
reed7503d602016-07-15 14:23:29 -07001429void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001431 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432 paint = &tmp;
1433 }
reed@google.com4b226022011-01-11 18:32:13 +00001434
reed@google.com8926b162012-03-23 15:36:36 +00001435 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001436
reed@android.com8a1c16f2008-12-17 15:59:43 +00001437 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001438 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001439 paint = &looper.paint();
1440 SkImageFilter* filter = paint->getImageFilter();
1441 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
senorblancof35566e2016-04-18 10:32:02 -07001442 if (filter) {
reeda2217ef2016-07-20 06:04:34 -07001443 dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001444 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001445 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001446 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001447 }
reeda2217ef2016-07-20 06:04:34 -07001448
reed@google.com4e2b3d32011-04-07 14:18:59 +00001449 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450}
1451
reed32704672015-12-16 08:27:10 -08001452/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001453
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001454void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001455 if (dx || dy) {
1456 this->checkForDeferredSave();
1457 fDeviceCMDirty = true;
1458 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001459
reedfe69b502016-09-12 06:31:48 -07001460 // Translate shouldn't affect the is-scale-translateness of the matrix.
1461 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001462
reedfe69b502016-09-12 06:31:48 -07001463 this->didTranslate(dx,dy);
1464 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001465}
1466
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001467void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001468 SkMatrix m;
1469 m.setScale(sx, sy);
1470 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001471}
1472
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001473void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001474 SkMatrix m;
1475 m.setRotate(degrees);
1476 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477}
1478
bungeman7438bfc2016-07-12 15:01:19 -07001479void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1480 SkMatrix m;
1481 m.setRotate(degrees, px, py);
1482 this->concat(m);
1483}
1484
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001485void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001486 SkMatrix m;
1487 m.setSkew(sx, sy);
1488 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001489}
1490
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001491void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001492 if (matrix.isIdentity()) {
1493 return;
1494 }
1495
reed2ff1fce2014-12-11 07:07:37 -08001496 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001497 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001498 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001499 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001500 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001501}
1502
reed8c30a812016-04-20 16:36:51 -07001503void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001504 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001505 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001506 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001507}
1508
1509void SkCanvas::setMatrix(const SkMatrix& matrix) {
1510 this->checkForDeferredSave();
1511 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001512 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001513}
1514
reed@android.com8a1c16f2008-12-17 15:59:43 +00001515void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001516 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001517}
1518
vjiaoblack95302da2016-07-21 10:25:54 -07001519#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001520void SkCanvas::translateZ(SkScalar z) {
1521 this->checkForDeferredSave();
1522 this->fMCRec->fCurDrawDepth += z;
1523 this->didTranslateZ(z);
1524}
1525
1526SkScalar SkCanvas::getZ() const {
1527 return this->fMCRec->fCurDrawDepth;
1528}
1529
vjiaoblack95302da2016-07-21 10:25:54 -07001530void SkCanvas::setLights(sk_sp<SkLights> lights) {
1531 this->fLights = lights;
1532}
1533
1534sk_sp<SkLights> SkCanvas::getLights() const {
1535 return this->fLights;
1536}
1537#endif
1538
reed@android.com8a1c16f2008-12-17 15:59:43 +00001539//////////////////////////////////////////////////////////////////////////////
1540
reed73603f32016-09-20 08:42:38 -07001541void SkCanvas::clipRect(const SkRect& rect, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001542 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001543 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1544 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001545}
1546
reed73603f32016-09-20 08:42:38 -07001547void SkCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) {
reed74467162016-06-30 08:15:35 -07001548 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate();
reedc64eff52015-11-21 12:39:45 -08001549 SkRect devR;
reed74467162016-06-30 08:15:35 -07001550 if (isScaleTrans) {
halcanaryc5769b22016-08-10 07:13:21 -07001551 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reedc64eff52015-11-21 12:39:45 -08001552 }
bsalomonac8cabd2015-11-20 18:53:07 -08001553
reed73603f32016-09-20 08:42:38 -07001554 if (kIntersect_Op == op && kHard_ClipEdgeStyle == edgeStyle && isScaleTrans) {
reedc64eff52015-11-21 12:39:45 -08001555 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1556#if 0
1557 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1558 rect.left(), rect.top(), rect.right(), rect.bottom());
1559#endif
1560 return;
1561 }
1562 }
1563
1564 AutoValidateClip avc(this);
1565
1566 fDeviceCMDirty = true;
reedc64eff52015-11-21 12:39:45 -08001567
reed74467162016-06-30 08:15:35 -07001568 if (isScaleTrans) {
reedc64eff52015-11-21 12:39:45 -08001569 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1570 fClipStack->clipDevRect(devR, op, isAA);
reed73603f32016-09-20 08:42:38 -07001571 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), (SkRegion::Op)op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001572 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001573 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001574 // and clip against that, since it can handle any matrix. However, to
1575 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1576 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001577 SkPath path;
1578
1579 path.addRect(rect);
bsalomonbdc335f2016-08-22 13:42:17 -07001580 path.setIsVolatile(true);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001581 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582 }
msarettfbfa2582016-08-12 08:29:08 -07001583
1584 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001585}
1586
reed73603f32016-09-20 08:42:38 -07001587void SkCanvas::clipRRect(const SkRRect& rrect, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001588 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001589 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001590 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001591 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1592 } else {
1593 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001594 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001595}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001596
reed73603f32016-09-20 08:42:38 -07001597void SkCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001598 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001599 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001600 AutoValidateClip avc(this);
1601
1602 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001603
reed687fa1c2015-04-07 08:00:56 -07001604 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001605
reed73603f32016-09-20 08:42:38 -07001606 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), (SkRegion::Op)op,
robertphillips125f19a2015-11-23 09:00:05 -08001607 kSoft_ClipEdgeStyle == edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001608 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001609 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001610 }
1611
1612 SkPath path;
1613 path.addRRect(rrect);
bsalomonbdc335f2016-08-22 13:42:17 -07001614 path.setIsVolatile(true);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001615 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001616 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001617}
1618
reed73603f32016-09-20 08:42:38 -07001619void SkCanvas::clipPath(const SkPath& path, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001620 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001621 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001622
1623 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1624 SkRect r;
1625 if (path.isRect(&r)) {
1626 this->onClipRect(r, op, edgeStyle);
1627 return;
1628 }
1629 SkRRect rrect;
1630 if (path.isOval(&r)) {
1631 rrect.setOval(r);
1632 this->onClipRRect(rrect, op, edgeStyle);
1633 return;
1634 }
1635 if (path.isRRect(&rrect)) {
1636 this->onClipRRect(rrect, op, edgeStyle);
1637 return;
1638 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001639 }
robertphillips39f05382015-11-24 09:30:12 -08001640
1641 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001642}
1643
reed73603f32016-09-20 08:42:38 -07001644void SkCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001645 AutoValidateClip avc(this);
1646
reed@android.com8a1c16f2008-12-17 15:59:43 +00001647 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648
1649 SkPath devPath;
bsalomonbdc335f2016-08-22 13:42:17 -07001650 if (fMCRec->fMatrix.isIdentity()) {
1651 devPath = path;
1652 } else {
1653 path.transform(fMCRec->fMatrix, &devPath);
1654 devPath.setIsVolatile(true);
1655 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001656
reed@google.comfe701122011-11-08 19:41:23 +00001657 // Check if the transfomation, or the original path itself
1658 // made us empty. Note this can also happen if we contained NaN
1659 // values. computing the bounds detects this, and will set our
1660 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1661 if (devPath.getBounds().isEmpty()) {
1662 // resetting the path will remove any NaN or other wanky values
1663 // that might upset our scan converter.
1664 devPath.reset();
1665 }
1666
reed@google.com5c3d1472011-02-22 19:12:23 +00001667 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001668 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001669
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001670 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001671 bool clipIsAA = getClipStack()->asPath(&devPath);
1672 if (clipIsAA) {
1673 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001674 }
fmalita1a481fe2015-02-04 07:39:34 -08001675
reed73603f32016-09-20 08:42:38 -07001676 op = kReplace_Op;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001677 }
1678
reed73603f32016-09-20 08:42:38 -07001679 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), (SkRegion::Op)op, edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001680 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681}
1682
reed73603f32016-09-20 08:42:38 -07001683void SkCanvas::clipRegion(const SkRegion& rgn, ClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001684 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001685 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001686}
1687
reed73603f32016-09-20 08:42:38 -07001688void SkCanvas::onClipRegion(const SkRegion& rgn, ClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001689 AutoValidateClip avc(this);
1690
reed@android.com8a1c16f2008-12-17 15:59:43 +00001691 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692
reed@google.com5c3d1472011-02-22 19:12:23 +00001693 // todo: signal fClipStack that we have a region, and therefore (I guess)
1694 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001695 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001696
reed73603f32016-09-20 08:42:38 -07001697 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001698 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001699}
1700
reed@google.com819c9212011-02-23 18:56:55 +00001701#ifdef SK_DEBUG
1702void SkCanvas::validateClip() const {
1703 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001704 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001705 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001706 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001707 return;
1708 }
1709
reed@google.com819c9212011-02-23 18:56:55 +00001710 SkIRect ir;
1711 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001712 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001713
reed687fa1c2015-04-07 08:00:56 -07001714 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001715 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001716 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001717 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001718 case SkClipStack::Element::kRect_Type:
1719 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001720 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001721 break;
1722 case SkClipStack::Element::kEmpty_Type:
1723 tmpClip.setEmpty();
1724 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001725 default: {
1726 SkPath path;
1727 element->asPath(&path);
reed73603f32016-09-20 08:42:38 -07001728 tmpClip.op(path, this->getTopLayerBounds(), (SkRegion::Op)element->getOp(),
1729 element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001730 break;
1731 }
reed@google.com819c9212011-02-23 18:56:55 +00001732 }
1733 }
reed@google.com819c9212011-02-23 18:56:55 +00001734}
1735#endif
1736
reed@google.com90c07ea2012-04-13 13:50:27 +00001737void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001738 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001739 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001740
halcanary96fcdcc2015-08-27 07:41:13 -07001741 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001742 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001743 }
1744}
1745
reed@google.com5c3d1472011-02-22 19:12:23 +00001746///////////////////////////////////////////////////////////////////////////////
1747
reed@google.com754de5f2014-02-24 19:38:20 +00001748bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001749 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001750}
1751
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001752bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001753 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001754}
1755
msarettfbfa2582016-08-12 08:29:08 -07001756static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1757#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1758 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1759 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1760 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1761 return 0xF != _mm_movemask_ps(mask);
1762#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1763 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1764 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1765 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1766 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1767#else
1768 SkRect devRectAsRect;
1769 SkRect devClipAsRect;
1770 devRect.store(&devRectAsRect.fLeft);
1771 devClip.store(&devClipAsRect.fLeft);
1772 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1773#endif
1774}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001775
msarettfbfa2582016-08-12 08:29:08 -07001776// It's important for this function to not be inlined. Otherwise the compiler will share code
1777// between the fast path and the slow path, resulting in two slow paths.
1778static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1779 const SkMatrix& matrix) {
1780 SkRect deviceRect;
1781 matrix.mapRect(&deviceRect, src);
1782 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1783}
1784
1785bool SkCanvas::quickReject(const SkRect& src) const {
1786#ifdef SK_DEBUG
1787 // Verify that fDeviceClipBounds are set properly.
1788 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001789 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001790 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001791 } else {
msarettfbfa2582016-08-12 08:29:08 -07001792 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001793 }
msarettfbfa2582016-08-12 08:29:08 -07001794
msarett9637ea92016-08-18 14:03:30 -07001795 // Verify that fIsScaleTranslate is set properly.
1796 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001797#endif
1798
msarett9637ea92016-08-18 14:03:30 -07001799 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001800 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1801 }
1802
1803 // We inline the implementation of mapScaleTranslate() for the fast path.
1804 float sx = fMCRec->fMatrix.getScaleX();
1805 float sy = fMCRec->fMatrix.getScaleY();
1806 float tx = fMCRec->fMatrix.getTranslateX();
1807 float ty = fMCRec->fMatrix.getTranslateY();
1808 Sk4f scale(sx, sy, sx, sy);
1809 Sk4f trans(tx, ty, tx, ty);
1810
1811 // Apply matrix.
1812 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1813
1814 // Make sure left < right, top < bottom.
1815 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1816 Sk4f min = Sk4f::Min(ltrb, rblt);
1817 Sk4f max = Sk4f::Max(ltrb, rblt);
1818 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1819 // ARM this sequence generates the fastest (a single instruction).
1820 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1821
1822 // Check if the device rect is NaN or outside the clip.
1823 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001824}
1825
reed@google.com3b3e8952012-08-16 20:53:31 +00001826bool SkCanvas::quickReject(const SkPath& path) const {
1827 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001828}
1829
reed@google.com3b3e8952012-08-16 20:53:31 +00001830bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001831 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001832 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001833 return false;
1834 }
1835
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001836 SkMatrix inverse;
1837 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001838 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001839 if (bounds) {
1840 bounds->setEmpty();
1841 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001842 return false;
1843 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001844
bsalomon49f085d2014-09-05 13:34:00 -07001845 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001846 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001847 // adjust it outwards in case we are antialiasing
1848 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001849
reed@google.com8f4d2302013-12-17 16:44:46 +00001850 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1851 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001852 inverse.mapRect(bounds, r);
1853 }
1854 return true;
1855}
1856
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001857bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001858 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001859 if (clip.isEmpty()) {
1860 if (bounds) {
1861 bounds->setEmpty();
1862 }
1863 return false;
1864 }
1865
bsalomon49f085d2014-09-05 13:34:00 -07001866 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001867 *bounds = clip.getBounds();
1868 }
1869 return true;
1870}
1871
reed@android.com8a1c16f2008-12-17 15:59:43 +00001872const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001873 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001874}
1875
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001876const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001877 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001878}
1879
robertphillips175dd9b2016-04-28 14:32:04 -07001880GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001881 SkBaseDevice* dev = this->getTopDevice();
robertphillips175dd9b2016-04-28 14:32:04 -07001882 return dev ? dev->accessDrawContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001883}
1884
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001885GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001886 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001887 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001888}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001889
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001890void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1891 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001892 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001893 if (outer.isEmpty()) {
1894 return;
1895 }
1896 if (inner.isEmpty()) {
1897 this->drawRRect(outer, paint);
1898 return;
1899 }
1900
1901 // We don't have this method (yet), but technically this is what we should
1902 // be able to assert...
1903 // SkASSERT(outer.contains(inner));
1904 //
1905 // For now at least check for containment of bounds
1906 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1907
1908 this->onDrawDRRect(outer, inner, paint);
1909}
1910
reed41af9662015-01-05 07:49:08 -08001911// These need to stop being virtual -- clients need to override the onDraw... versions
1912
1913void SkCanvas::drawPaint(const SkPaint& paint) {
1914 this->onDrawPaint(paint);
1915}
1916
1917void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1918 this->onDrawRect(r, paint);
1919}
1920
msarettdca352e2016-08-26 06:37:45 -07001921void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1922 if (region.isEmpty()) {
1923 return;
1924 }
1925
1926 if (region.isRect()) {
1927 return this->drawIRect(region.getBounds(), paint);
1928 }
1929
1930 this->onDrawRegion(region, paint);
1931}
1932
reed41af9662015-01-05 07:49:08 -08001933void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1934 this->onDrawOval(r, paint);
1935}
1936
1937void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1938 this->onDrawRRect(rrect, paint);
1939}
1940
1941void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1942 this->onDrawPoints(mode, count, pts, paint);
1943}
1944
1945void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1946 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1947 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1948 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1949 indices, indexCount, paint);
1950}
1951
1952void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1953 this->onDrawPath(path, paint);
1954}
1955
reeda85d4d02015-05-06 12:56:48 -07001956void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001957 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001958 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001959}
1960
reede47829b2015-08-06 10:02:53 -07001961void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1962 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001963 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001964 if (dst.isEmpty() || src.isEmpty()) {
1965 return;
1966 }
1967 this->onDrawImageRect(image, &src, dst, paint, constraint);
1968}
reed41af9662015-01-05 07:49:08 -08001969
reed84984ef2015-07-17 07:09:43 -07001970void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1971 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001972 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001973 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001974}
1975
reede47829b2015-08-06 10:02:53 -07001976void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1977 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001978 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001979 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1980 constraint);
1981}
reede47829b2015-08-06 10:02:53 -07001982
reed4c21dc52015-06-25 12:32:03 -07001983void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1984 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001985 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001986 if (dst.isEmpty()) {
1987 return;
1988 }
msarett552bca92016-08-03 06:53:26 -07001989 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1990 this->onDrawImageNine(image, center, dst, paint);
1991 } else {
reede47829b2015-08-06 10:02:53 -07001992 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001993 }
reed4c21dc52015-06-25 12:32:03 -07001994}
1995
msarett16882062016-08-16 09:31:08 -07001996void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1997 const SkPaint* paint) {
1998 RETURN_ON_NULL(image);
1999 if (dst.isEmpty()) {
2000 return;
2001 }
msarett71df2d72016-09-30 12:41:42 -07002002
2003 SkIRect bounds;
2004 Lattice latticePlusBounds = lattice;
2005 if (!latticePlusBounds.fBounds) {
2006 bounds = SkIRect::MakeWH(image->width(), image->height());
2007 latticePlusBounds.fBounds = &bounds;
2008 }
2009
2010 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
2011 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07002012 } else {
2013 this->drawImageRect(image, dst, paint);
2014 }
2015}
2016
reed41af9662015-01-05 07:49:08 -08002017void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002018 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002019 return;
2020 }
reed41af9662015-01-05 07:49:08 -08002021 this->onDrawBitmap(bitmap, dx, dy, paint);
2022}
2023
reede47829b2015-08-06 10:02:53 -07002024void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002025 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002026 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002027 return;
2028 }
reede47829b2015-08-06 10:02:53 -07002029 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002030}
2031
reed84984ef2015-07-17 07:09:43 -07002032void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2033 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002034 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002035}
2036
reede47829b2015-08-06 10:02:53 -07002037void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2038 SrcRectConstraint constraint) {
2039 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2040 constraint);
2041}
reede47829b2015-08-06 10:02:53 -07002042
reed41af9662015-01-05 07:49:08 -08002043void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2044 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002045 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002046 return;
2047 }
msarett552bca92016-08-03 06:53:26 -07002048 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2049 this->onDrawBitmapNine(bitmap, center, dst, paint);
2050 } else {
reeda5517e22015-07-14 10:54:12 -07002051 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002052 }
reed41af9662015-01-05 07:49:08 -08002053}
2054
msarettc573a402016-08-02 08:05:56 -07002055void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2056 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002057 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002058 return;
2059 }
msarett71df2d72016-09-30 12:41:42 -07002060
2061 SkIRect bounds;
2062 Lattice latticePlusBounds = lattice;
2063 if (!latticePlusBounds.fBounds) {
2064 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2065 latticePlusBounds.fBounds = &bounds;
2066 }
2067
2068 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2069 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002070 } else {
msarett16882062016-08-16 09:31:08 -07002071 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002072 }
msarettc573a402016-08-02 08:05:56 -07002073}
2074
reed71c3c762015-06-24 10:29:17 -07002075void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2076 const SkColor colors[], int count, SkXfermode::Mode mode,
2077 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002078 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002079 if (count <= 0) {
2080 return;
2081 }
2082 SkASSERT(atlas);
2083 SkASSERT(xform);
2084 SkASSERT(tex);
2085 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2086}
2087
reedf70b5312016-03-04 16:36:20 -08002088void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2089 if (key) {
2090 this->onDrawAnnotation(rect, key, value);
2091 }
2092}
2093
reede47829b2015-08-06 10:02:53 -07002094void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2095 const SkPaint* paint, SrcRectConstraint constraint) {
2096 if (src) {
2097 this->drawImageRect(image, *src, dst, paint, constraint);
2098 } else {
2099 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2100 dst, paint, constraint);
2101 }
2102}
2103void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2104 const SkPaint* paint, SrcRectConstraint constraint) {
2105 if (src) {
2106 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2107 } else {
2108 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2109 dst, paint, constraint);
2110 }
2111}
2112
tomhudsoncb3bd182016-05-18 07:24:16 -07002113void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2114 SkIRect layer_bounds = this->getTopLayerBounds();
2115 if (matrix) {
2116 *matrix = this->getTotalMatrix();
2117 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2118 }
2119 if (clip_bounds) {
2120 this->getClipDeviceBounds(clip_bounds);
2121 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2122 }
2123}
2124
reed@android.com8a1c16f2008-12-17 15:59:43 +00002125//////////////////////////////////////////////////////////////////////////////
2126// These are the virtual drawing methods
2127//////////////////////////////////////////////////////////////////////////////
2128
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002129void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002130 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002131 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2132 }
2133}
2134
reed41af9662015-01-05 07:49:08 -08002135void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002136 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002137 this->internalDrawPaint(paint);
2138}
2139
2140void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002141 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002142
2143 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002144 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145 }
2146
reed@google.com4e2b3d32011-04-07 14:18:59 +00002147 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002148}
2149
reed41af9662015-01-05 07:49:08 -08002150void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2151 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002152 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002153 if ((long)count <= 0) {
2154 return;
2155 }
2156
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002157 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002158 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002159 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002160 // special-case 2 points (common for drawing a single line)
2161 if (2 == count) {
2162 r.set(pts[0], pts[1]);
2163 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002164 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002165 }
senorblanco87e066e2015-10-28 11:23:36 -07002166 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2167 return;
2168 }
2169 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002170 }
reed@google.coma584aed2012-05-16 14:06:02 +00002171
halcanary96fcdcc2015-08-27 07:41:13 -07002172 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002173
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002174 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002175
reed@android.com8a1c16f2008-12-17 15:59:43 +00002176 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002177 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002178 }
reed@google.com4b226022011-01-11 18:32:13 +00002179
reed@google.com4e2b3d32011-04-07 14:18:59 +00002180 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002181}
2182
reed4a167172016-08-18 17:15:25 -07002183static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2184 return ((intptr_t)paint.getImageFilter() |
2185#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2186 (intptr_t)canvas->getDrawFilter() |
2187#endif
2188 (intptr_t)paint.getLooper() ) != 0;
2189}
2190
reed41af9662015-01-05 07:49:08 -08002191void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002192 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002193 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002194 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002195 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002196 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2197 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2198 SkRect tmp(r);
2199 tmp.sort();
2200
senorblanco87e066e2015-10-28 11:23:36 -07002201 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2202 return;
2203 }
2204 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002205 }
reed@google.com4b226022011-01-11 18:32:13 +00002206
reed4a167172016-08-18 17:15:25 -07002207 if (needs_autodrawlooper(this, paint)) {
2208 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002209
reed4a167172016-08-18 17:15:25 -07002210 while (iter.next()) {
2211 iter.fDevice->drawRect(iter, r, looper.paint());
2212 }
2213
2214 LOOPER_END
2215 } else {
2216 this->predrawNotify(bounds, &paint, false);
2217 SkDrawIter iter(this);
2218 while (iter.next()) {
2219 iter.fDevice->drawRect(iter, r, paint);
2220 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002221 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002222}
2223
msarett44df6512016-08-25 13:54:30 -07002224void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2225 SkRect storage;
2226 SkRect regionRect = SkRect::Make(region.getBounds());
2227 const SkRect* bounds = nullptr;
2228 if (paint.canComputeFastBounds()) {
2229 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2230 return;
2231 }
2232 bounds = &regionRect;
2233 }
2234
2235 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2236
2237 while (iter.next()) {
2238 iter.fDevice->drawRegion(iter, region, looper.paint());
2239 }
2240
2241 LOOPER_END
2242}
2243
reed41af9662015-01-05 07:49:08 -08002244void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002245 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002246 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002247 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002248 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002249 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2250 return;
2251 }
2252 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002253 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002254
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002255 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002256
2257 while (iter.next()) {
2258 iter.fDevice->drawOval(iter, oval, looper.paint());
2259 }
2260
2261 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002262}
2263
bsalomonac3aa242016-08-19 11:25:19 -07002264void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2265 SkScalar sweepAngle, bool useCenter,
2266 const SkPaint& paint) {
2267 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2268 const SkRect* bounds = nullptr;
2269 if (paint.canComputeFastBounds()) {
2270 SkRect storage;
2271 // Note we're using the entire oval as the bounds.
2272 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2273 return;
2274 }
2275 bounds = &oval;
2276 }
2277
2278 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2279
2280 while (iter.next()) {
2281 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2282 }
2283
2284 LOOPER_END
2285}
2286
reed41af9662015-01-05 07:49:08 -08002287void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002288 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002289 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002290 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002291 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002292 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2293 return;
2294 }
2295 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002296 }
2297
2298 if (rrect.isRect()) {
2299 // call the non-virtual version
2300 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002301 return;
2302 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002303 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002304 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2305 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002306 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002307
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002308 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002309
2310 while (iter.next()) {
2311 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2312 }
2313
2314 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002315}
2316
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002317void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2318 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002319 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002320 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002321 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002322 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2323 return;
2324 }
2325 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002326 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002327
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002328 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002329
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002330 while (iter.next()) {
2331 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2332 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002333
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002334 LOOPER_END
2335}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002336
reed41af9662015-01-05 07:49:08 -08002337void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002338 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002339 if (!path.isFinite()) {
2340 return;
2341 }
2342
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002343 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002344 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002345 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002346 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002347 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2348 return;
2349 }
2350 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002351 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002352
2353 const SkRect& r = path.getBounds();
2354 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002355 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002356 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002357 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002358 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002359 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002360
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002361 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002362
2363 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002364 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002365 }
2366
reed@google.com4e2b3d32011-04-07 14:18:59 +00002367 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002368}
2369
reed262a71b2015-12-05 13:07:27 -08002370bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002371 if (!paint.getImageFilter()) {
2372 return false;
2373 }
2374
2375 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002376 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002377 return false;
2378 }
2379
2380 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2381 // Once we can filter and the filter will return a result larger than itself, we should be
2382 // able to remove this constraint.
2383 // skbug.com/4526
2384 //
2385 SkPoint pt;
2386 ctm.mapXY(x, y, &pt);
2387 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2388 return ir.contains(fMCRec->fRasterClip.getBounds());
2389}
2390
reeda85d4d02015-05-06 12:56:48 -07002391void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002392 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002393 SkRect bounds = SkRect::MakeXYWH(x, y,
2394 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002395 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002396 SkRect tmp = bounds;
2397 if (paint) {
2398 paint->computeFastBounds(tmp, &tmp);
2399 }
2400 if (this->quickReject(tmp)) {
2401 return;
2402 }
reeda85d4d02015-05-06 12:56:48 -07002403 }
halcanary9d524f22016-03-29 09:03:52 -07002404
reeda85d4d02015-05-06 12:56:48 -07002405 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002406 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002407 paint = lazy.init();
2408 }
reed262a71b2015-12-05 13:07:27 -08002409
reeda2217ef2016-07-20 06:04:34 -07002410 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002411 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2412 *paint);
2413 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002414 special = this->getDevice()->makeSpecial(image);
2415 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002416 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002417 }
2418 }
2419
reed262a71b2015-12-05 13:07:27 -08002420 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2421
reeda85d4d02015-05-06 12:56:48 -07002422 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002423 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002424 if (special) {
2425 SkPoint pt;
2426 iter.fMatrix->mapXY(x, y, &pt);
2427 iter.fDevice->drawSpecial(iter, special.get(),
2428 SkScalarRoundToInt(pt.fX),
2429 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002430 } else {
2431 iter.fDevice->drawImage(iter, image, x, y, pnt);
2432 }
reeda85d4d02015-05-06 12:56:48 -07002433 }
halcanary9d524f22016-03-29 09:03:52 -07002434
reeda85d4d02015-05-06 12:56:48 -07002435 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002436}
2437
reed41af9662015-01-05 07:49:08 -08002438void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002439 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002440 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002441 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002442 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002443 if (paint) {
2444 paint->computeFastBounds(dst, &storage);
2445 }
2446 if (this->quickReject(storage)) {
2447 return;
2448 }
reeda85d4d02015-05-06 12:56:48 -07002449 }
2450 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002451 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002452 paint = lazy.init();
2453 }
halcanary9d524f22016-03-29 09:03:52 -07002454
senorblancoc41e7e12015-12-07 12:51:30 -08002455 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002456 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002457
reeda85d4d02015-05-06 12:56:48 -07002458 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002459 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002460 }
halcanary9d524f22016-03-29 09:03:52 -07002461
reeda85d4d02015-05-06 12:56:48 -07002462 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002463}
2464
reed41af9662015-01-05 07:49:08 -08002465void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002466 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002467 SkDEBUGCODE(bitmap.validate();)
2468
reed33366972015-10-08 09:22:02 -07002469 if (bitmap.drawsNothing()) {
2470 return;
2471 }
2472
2473 SkLazyPaint lazy;
2474 if (nullptr == paint) {
2475 paint = lazy.init();
2476 }
2477
2478 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2479
2480 SkRect storage;
2481 const SkRect* bounds = nullptr;
2482 if (paint->canComputeFastBounds()) {
2483 bitmap.getBounds(&storage);
2484 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002485 SkRect tmp = storage;
2486 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2487 return;
2488 }
2489 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002490 }
reed@google.com4b226022011-01-11 18:32:13 +00002491
reeda2217ef2016-07-20 06:04:34 -07002492 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002493 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2494 *paint);
2495 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002496 special = this->getDevice()->makeSpecial(bitmap);
2497 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002498 drawAsSprite = false;
2499 }
2500 }
2501
reed262a71b2015-12-05 13:07:27 -08002502 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002503
2504 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002505 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002506 if (special) {
reed262a71b2015-12-05 13:07:27 -08002507 SkPoint pt;
2508 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002509 iter.fDevice->drawSpecial(iter, special.get(),
2510 SkScalarRoundToInt(pt.fX),
2511 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002512 } else {
2513 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2514 }
reed33366972015-10-08 09:22:02 -07002515 }
msarettfbfa2582016-08-12 08:29:08 -07002516
reed33366972015-10-08 09:22:02 -07002517 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002518}
2519
reed@google.com9987ec32011-09-07 11:57:52 +00002520// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002521void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002522 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002523 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002524 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002525 return;
2526 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002527
halcanary96fcdcc2015-08-27 07:41:13 -07002528 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002529 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002530 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2531 return;
2532 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002533 }
reed@google.com3d608122011-11-21 15:16:16 +00002534
reed@google.com33535f32012-09-25 15:37:50 +00002535 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002536 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002537 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002538 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002539
senorblancoc41e7e12015-12-07 12:51:30 -08002540 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002541 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002542
reed@google.com33535f32012-09-25 15:37:50 +00002543 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002544 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002545 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002546
reed@google.com33535f32012-09-25 15:37:50 +00002547 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002548}
2549
reed41af9662015-01-05 07:49:08 -08002550void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002551 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002552 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002553 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002554 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002555}
2556
reed4c21dc52015-06-25 12:32:03 -07002557void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2558 const SkPaint* paint) {
2559 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002560
halcanary96fcdcc2015-08-27 07:41:13 -07002561 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002562 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002563 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2564 return;
2565 }
reed@google.com3d608122011-11-21 15:16:16 +00002566 }
halcanary9d524f22016-03-29 09:03:52 -07002567
reed4c21dc52015-06-25 12:32:03 -07002568 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002569 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002570 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002571 }
halcanary9d524f22016-03-29 09:03:52 -07002572
senorblancoc41e7e12015-12-07 12:51:30 -08002573 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002574
reed4c21dc52015-06-25 12:32:03 -07002575 while (iter.next()) {
2576 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002577 }
halcanary9d524f22016-03-29 09:03:52 -07002578
reed4c21dc52015-06-25 12:32:03 -07002579 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002580}
2581
reed41af9662015-01-05 07:49:08 -08002582void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2583 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002584 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002585 SkDEBUGCODE(bitmap.validate();)
2586
halcanary96fcdcc2015-08-27 07:41:13 -07002587 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002588 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002589 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2590 return;
2591 }
reed4c21dc52015-06-25 12:32:03 -07002592 }
halcanary9d524f22016-03-29 09:03:52 -07002593
reed4c21dc52015-06-25 12:32:03 -07002594 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002595 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002596 paint = lazy.init();
2597 }
halcanary9d524f22016-03-29 09:03:52 -07002598
senorblancoc41e7e12015-12-07 12:51:30 -08002599 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002600
reed4c21dc52015-06-25 12:32:03 -07002601 while (iter.next()) {
2602 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2603 }
halcanary9d524f22016-03-29 09:03:52 -07002604
reed4c21dc52015-06-25 12:32:03 -07002605 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002606}
2607
msarett16882062016-08-16 09:31:08 -07002608void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2609 const SkPaint* paint) {
2610 if (nullptr == paint || paint->canComputeFastBounds()) {
2611 SkRect storage;
2612 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2613 return;
2614 }
2615 }
2616
2617 SkLazyPaint lazy;
2618 if (nullptr == paint) {
2619 paint = lazy.init();
2620 }
2621
2622 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2623
2624 while (iter.next()) {
2625 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2626 }
2627
2628 LOOPER_END
2629}
2630
2631void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2632 const SkRect& dst, const SkPaint* paint) {
2633 if (nullptr == paint || paint->canComputeFastBounds()) {
2634 SkRect storage;
2635 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2636 return;
2637 }
2638 }
2639
2640 SkLazyPaint lazy;
2641 if (nullptr == paint) {
2642 paint = lazy.init();
2643 }
2644
2645 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2646
2647 while (iter.next()) {
2648 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2649 }
2650
2651 LOOPER_END
2652}
2653
reed@google.comf67e4cf2011-03-15 20:56:58 +00002654class SkDeviceFilteredPaint {
2655public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002656 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002657 uint32_t filteredFlags = device->filterTextFlags(paint);
2658 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002659 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002660 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002661 fPaint = newPaint;
2662 } else {
2663 fPaint = &paint;
2664 }
2665 }
2666
reed@google.comf67e4cf2011-03-15 20:56:58 +00002667 const SkPaint& paint() const { return *fPaint; }
2668
2669private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002670 const SkPaint* fPaint;
2671 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002672};
2673
bungeman@google.com52c748b2011-08-22 21:30:43 +00002674void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2675 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002676 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002677 draw.fDevice->drawRect(draw, r, paint);
2678 } else {
2679 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002680 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002681 draw.fDevice->drawRect(draw, r, p);
2682 }
2683}
2684
2685void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2686 const char text[], size_t byteLength,
2687 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002688 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002689
2690 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002691 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002692 draw.fRC->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002693 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002694 return;
2695 }
2696
2697 SkScalar width = 0;
2698 SkPoint start;
2699
2700 start.set(0, 0); // to avoid warning
2701 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2702 SkPaint::kStrikeThruText_Flag)) {
2703 width = paint.measureText(text, byteLength);
2704
2705 SkScalar offsetX = 0;
2706 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2707 offsetX = SkScalarHalf(width);
2708 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2709 offsetX = width;
2710 }
2711 start.set(x - offsetX, y);
2712 }
2713
2714 if (0 == width) {
2715 return;
2716 }
2717
2718 uint32_t flags = paint.getFlags();
2719
2720 if (flags & (SkPaint::kUnderlineText_Flag |
2721 SkPaint::kStrikeThruText_Flag)) {
2722 SkScalar textSize = paint.getTextSize();
2723 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2724 SkRect r;
2725
2726 r.fLeft = start.fX;
2727 r.fRight = start.fX + width;
2728
2729 if (flags & SkPaint::kUnderlineText_Flag) {
2730 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2731 start.fY);
2732 r.fTop = offset;
2733 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002734 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002735 }
2736 if (flags & SkPaint::kStrikeThruText_Flag) {
2737 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2738 start.fY);
2739 r.fTop = offset;
2740 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002741 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002742 }
2743 }
2744}
2745
reed@google.come0d9ce82014-04-23 04:00:17 +00002746void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2747 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002748 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002749
2750 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002751 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002752 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002753 DrawTextDecorations(iter, dfp.paint(),
2754 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002755 }
2756
reed@google.com4e2b3d32011-04-07 14:18:59 +00002757 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758}
2759
reed@google.come0d9ce82014-04-23 04:00:17 +00002760void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2761 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002762 SkPoint textOffset = SkPoint::Make(0, 0);
2763
halcanary96fcdcc2015-08-27 07:41:13 -07002764 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002765
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002767 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002768 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002769 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002771
reed@google.com4e2b3d32011-04-07 14:18:59 +00002772 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002773}
2774
reed@google.come0d9ce82014-04-23 04:00:17 +00002775void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2776 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002777
2778 SkPoint textOffset = SkPoint::Make(0, constY);
2779
halcanary96fcdcc2015-08-27 07:41:13 -07002780 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002781
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002783 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002784 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002785 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002787
reed@google.com4e2b3d32011-04-07 14:18:59 +00002788 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002789}
2790
reed@google.come0d9ce82014-04-23 04:00:17 +00002791void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2792 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002793 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002794
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795 while (iter.next()) {
2796 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002797 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002799
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002800 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002801}
2802
reed45561a02016-07-07 12:47:17 -07002803void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2804 const SkRect* cullRect, const SkPaint& paint) {
2805 if (cullRect && this->quickReject(*cullRect)) {
2806 return;
2807 }
2808
2809 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2810
2811 while (iter.next()) {
2812 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2813 }
2814
2815 LOOPER_END
2816}
2817
fmalita00d5c2c2014-08-21 08:53:26 -07002818void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2819 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002820
fmalita85d5eb92015-03-04 11:20:12 -08002821 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002822 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002823 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002824 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002825 SkRect tmp;
2826 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2827 return;
2828 }
2829 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002830 }
2831
fmalita024f9962015-03-03 19:08:17 -08002832 // We cannot filter in the looper as we normally do, because the paint is
2833 // incomplete at this point (text-related attributes are embedded within blob run paints).
2834 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002835 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002836
fmalita85d5eb92015-03-04 11:20:12 -08002837 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002838
fmalitaaa1b9122014-08-28 14:32:24 -07002839 while (iter.next()) {
2840 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002841 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002842 }
2843
fmalitaaa1b9122014-08-28 14:32:24 -07002844 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002845
2846 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002847}
2848
reed@google.come0d9ce82014-04-23 04:00:17 +00002849// These will become non-virtual, so they always call the (virtual) onDraw... method
2850void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2851 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002852 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002853 if (byteLength) {
2854 this->onDrawText(text, byteLength, x, y, paint);
2855 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002856}
2857void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2858 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002859 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002860 if (byteLength) {
2861 this->onDrawPosText(text, byteLength, pos, paint);
2862 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002863}
2864void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2865 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002866 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002867 if (byteLength) {
2868 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2869 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002870}
2871void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2872 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002873 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002874 if (byteLength) {
2875 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2876 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002877}
reed45561a02016-07-07 12:47:17 -07002878void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2879 const SkRect* cullRect, const SkPaint& paint) {
2880 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2881 if (byteLength) {
2882 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2883 }
2884}
fmalita00d5c2c2014-08-21 08:53:26 -07002885void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2886 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002887 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002888 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002889 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002890}
reed@google.come0d9ce82014-04-23 04:00:17 +00002891
reed41af9662015-01-05 07:49:08 -08002892void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2893 const SkPoint verts[], const SkPoint texs[],
2894 const SkColor colors[], SkXfermode* xmode,
2895 const uint16_t indices[], int indexCount,
2896 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002897 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002898 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002899
reed@android.com8a1c16f2008-12-17 15:59:43 +00002900 while (iter.next()) {
2901 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002902 colors, xmode, indices, indexCount,
2903 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002904 }
reed@google.com4b226022011-01-11 18:32:13 +00002905
reed@google.com4e2b3d32011-04-07 14:18:59 +00002906 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002907}
2908
dandovb3c9d1c2014-08-12 08:34:29 -07002909void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2910 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002911 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002912 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002913 return;
2914 }
mtklein6cfa73a2014-08-13 13:33:49 -07002915
msarett9340c262016-09-22 05:20:21 -07002916 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2917}
2918
2919void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2920 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002921 // Since a patch is always within the convex hull of the control points, we discard it when its
2922 // bounding rectangle is completely outside the current clip.
2923 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002924 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002925 if (this->quickReject(bounds)) {
2926 return;
2927 }
mtklein6cfa73a2014-08-13 13:33:49 -07002928
halcanary96fcdcc2015-08-27 07:41:13 -07002929 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002930
dandovecfff212014-08-04 10:02:00 -07002931 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002932 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002933 }
mtklein6cfa73a2014-08-13 13:33:49 -07002934
dandovecfff212014-08-04 10:02:00 -07002935 LOOPER_END
2936}
2937
reeda8db7282015-07-07 10:22:31 -07002938void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002939 RETURN_ON_NULL(dr);
2940 if (x || y) {
2941 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2942 this->onDrawDrawable(dr, &matrix);
2943 } else {
2944 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002945 }
2946}
2947
reeda8db7282015-07-07 10:22:31 -07002948void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002949 RETURN_ON_NULL(dr);
2950 if (matrix && matrix->isIdentity()) {
2951 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002952 }
reede3b38ce2016-01-08 09:18:44 -08002953 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002954}
2955
2956void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2957 SkRect bounds = dr->getBounds();
2958 if (matrix) {
2959 matrix->mapRect(&bounds);
2960 }
2961 if (this->quickReject(bounds)) {
2962 return;
2963 }
2964 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002965}
2966
reed71c3c762015-06-24 10:29:17 -07002967void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2968 const SkColor colors[], int count, SkXfermode::Mode mode,
2969 const SkRect* cull, const SkPaint* paint) {
2970 if (cull && this->quickReject(*cull)) {
2971 return;
2972 }
2973
2974 SkPaint pnt;
2975 if (paint) {
2976 pnt = *paint;
2977 }
halcanary9d524f22016-03-29 09:03:52 -07002978
halcanary96fcdcc2015-08-27 07:41:13 -07002979 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002980 while (iter.next()) {
2981 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2982 }
2983 LOOPER_END
2984}
2985
reedf70b5312016-03-04 16:36:20 -08002986void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2987 SkASSERT(key);
2988
2989 SkPaint paint;
2990 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2991 while (iter.next()) {
2992 iter.fDevice->drawAnnotation(iter, rect, key, value);
2993 }
2994 LOOPER_END
2995}
2996
reed@android.com8a1c16f2008-12-17 15:59:43 +00002997//////////////////////////////////////////////////////////////////////////////
2998// These methods are NOT virtual, and therefore must call back into virtual
2999// methods, rather than actually drawing themselves.
3000//////////////////////////////////////////////////////////////////////////////
3001
3002void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00003003 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003004 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003005 SkPaint paint;
3006
3007 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00003008 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003009 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003010 }
3011 this->drawPaint(paint);
3012}
3013
reed@android.com845fdac2009-06-23 03:01:32 +00003014void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003015 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003016 SkPaint paint;
3017
3018 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00003019 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003020 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003021 }
3022 this->drawPaint(paint);
3023}
3024
3025void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003026 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003027 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00003028
reed@android.com8a1c16f2008-12-17 15:59:43 +00003029 pt.set(x, y);
3030 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3031}
3032
3033void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003034 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003035 SkPoint pt;
3036 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003037
reed@android.com8a1c16f2008-12-17 15:59:43 +00003038 pt.set(x, y);
3039 paint.setColor(color);
3040 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3041}
3042
3043void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3044 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003045 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003046 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003047
reed@android.com8a1c16f2008-12-17 15:59:43 +00003048 pts[0].set(x0, y0);
3049 pts[1].set(x1, y1);
3050 this->drawPoints(kLines_PointMode, 2, pts, paint);
3051}
3052
3053void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3054 SkScalar right, SkScalar bottom,
3055 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003056 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003057 SkRect r;
3058
3059 r.set(left, top, right, bottom);
3060 this->drawRect(r, paint);
3061}
3062
3063void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3064 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003065 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003066 if (radius < 0) {
3067 radius = 0;
3068 }
3069
3070 SkRect r;
3071 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003072 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003073}
3074
3075void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3076 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003077 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003078 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003079 SkRRect rrect;
3080 rrect.setRectXY(r, rx, ry);
3081 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003082 } else {
3083 this->drawRect(r, paint);
3084 }
3085}
3086
reed@android.com8a1c16f2008-12-17 15:59:43 +00003087void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3088 SkScalar sweepAngle, bool useCenter,
3089 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003090 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003091 if (oval.isEmpty() || !sweepAngle) {
3092 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003093 }
bsalomon21af9ca2016-08-25 12:29:23 -07003094 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003095}
3096
3097void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3098 const SkPath& path, SkScalar hOffset,
3099 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003100 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003101 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003102
reed@android.com8a1c16f2008-12-17 15:59:43 +00003103 matrix.setTranslate(hOffset, vOffset);
3104 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3105}
3106
reed@android.comf76bacf2009-05-13 14:00:33 +00003107///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003108
3109/**
3110 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3111 * against the playback cost of recursing into the subpicture to get at its actual ops.
3112 *
3113 * For now we pick a conservatively small value, though measurement (and other heuristics like
3114 * the type of ops contained) may justify changing this value.
3115 */
3116#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003117
reedd5fa1a42014-08-09 11:08:05 -07003118void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003119 RETURN_ON_NULL(picture);
3120
reed1c2c4412015-04-30 13:09:24 -07003121 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003122 if (matrix && matrix->isIdentity()) {
3123 matrix = nullptr;
3124 }
3125 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3126 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3127 picture->playback(this);
3128 } else {
3129 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003130 }
3131}
robertphillips9b14f262014-06-04 05:40:44 -07003132
reedd5fa1a42014-08-09 11:08:05 -07003133void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3134 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003135 if (!paint || paint->canComputeFastBounds()) {
3136 SkRect bounds = picture->cullRect();
3137 if (paint) {
3138 paint->computeFastBounds(bounds, &bounds);
3139 }
3140 if (matrix) {
3141 matrix->mapRect(&bounds);
3142 }
3143 if (this->quickReject(bounds)) {
3144 return;
3145 }
3146 }
3147
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003148 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003149 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003150}
3151
vjiaoblack95302da2016-07-21 10:25:54 -07003152#ifdef SK_EXPERIMENTAL_SHADOWING
3153void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3154 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003155 const SkPaint* paint,
3156 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003157 RETURN_ON_NULL(picture);
3158
3159 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3160
vjiaoblacke6f5d562016-08-25 06:30:23 -07003161 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003162}
3163
3164void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3165 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003166 const SkPaint* paint,
3167 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003168 if (!paint || paint->canComputeFastBounds()) {
3169 SkRect bounds = picture->cullRect();
3170 if (paint) {
3171 paint->computeFastBounds(bounds, &bounds);
3172 }
3173 if (matrix) {
3174 matrix->mapRect(&bounds);
3175 }
3176 if (this->quickReject(bounds)) {
3177 return;
3178 }
3179 }
3180
3181 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3182
vjiaoblacke6f5d562016-08-25 06:30:23 -07003183 sk_sp<SkImage> povDepthMap;
3184 sk_sp<SkImage> diffuseMap;
3185
vjiaoblack904527d2016-08-09 09:32:09 -07003186 // povDepthMap
3187 {
3188 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003189 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3190 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003191 sk_sp<SkLights> povLight = builder.finish();
3192
3193 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3194 picture->cullRect().height(),
3195 kBGRA_8888_SkColorType,
3196 kOpaque_SkAlphaType);
3197
3198 // Create a new surface (that matches the backend of canvas)
3199 // to create the povDepthMap
3200 sk_sp<SkSurface> surf(this->makeSurface(info));
3201
3202 // Wrap another SPFCanvas around the surface
3203 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3204 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3205
3206 // set the depth map canvas to have the light as the user's POV
3207 depthMapCanvas->setLights(std::move(povLight));
3208
3209 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003210 povDepthMap = surf->makeImageSnapshot();
3211 }
3212
3213 // diffuseMap
3214 {
3215 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3216 picture->cullRect().height(),
3217 kBGRA_8888_SkColorType,
3218 kOpaque_SkAlphaType);
3219
3220 sk_sp<SkSurface> surf(this->makeSurface(info));
3221 surf->getCanvas()->drawPicture(picture);
3222
3223 diffuseMap = surf->makeImageSnapshot();
3224 }
vjiaoblack904527d2016-08-09 09:32:09 -07003225
3226 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3227 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003228 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3229 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003230
3231 // TODO: pass the depth to the shader in vertices, or uniforms
3232 // so we don't have to render depth and color separately
3233 for (int i = 0; i < fLights->numLights(); ++i) {
3234 // skip over ambient lights; they don't cast shadows
3235 // lights that have shadow maps do not need updating (because lights are immutable)
3236 sk_sp<SkImage> depthMap;
3237 SkISize shMapSize;
3238
3239 if (fLights->light(i).getShadowMap() != nullptr) {
3240 continue;
3241 }
3242
3243 if (fLights->light(i).isRadial()) {
3244 shMapSize.fHeight = 1;
3245 shMapSize.fWidth = (int) picture->cullRect().width();
3246
3247 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3248 kBGRA_8888_SkColorType,
3249 kOpaque_SkAlphaType);
3250
3251 // Create new surface (that matches the backend of canvas)
3252 // for each shadow map
3253 sk_sp<SkSurface> surf(this->makeSurface(info));
3254
3255 // Wrap another SPFCanvas around the surface
3256 SkCanvas* depthMapCanvas = surf->getCanvas();
3257
3258 SkLights::Builder builder;
3259 builder.add(fLights->light(i));
3260 sk_sp<SkLights> curLight = builder.finish();
3261
3262 sk_sp<SkShader> shadowMapShader;
3263 shadowMapShader = SkRadialShadowMapShader::Make(
3264 povDepthShader, curLight,
3265 (int) picture->cullRect().width(),
3266 (int) picture->cullRect().height());
3267
3268 SkPaint shadowMapPaint;
3269 shadowMapPaint.setShader(std::move(shadowMapShader));
3270
3271 depthMapCanvas->setLights(curLight);
3272
3273 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3274 diffuseMap->height()),
3275 shadowMapPaint);
3276
3277 depthMap = surf->makeImageSnapshot();
3278
3279 } else {
3280 // TODO: compute the correct size of the depth map from the light properties
3281 // TODO: maybe add a kDepth_8_SkColorType
3282 // TODO: find actual max depth of picture
3283 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3284 fLights->light(i), 255,
3285 (int) picture->cullRect().width(),
3286 (int) picture->cullRect().height());
3287
3288 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3289 kBGRA_8888_SkColorType,
3290 kOpaque_SkAlphaType);
3291
3292 // Create a new surface (that matches the backend of canvas)
3293 // for each shadow map
3294 sk_sp<SkSurface> surf(this->makeSurface(info));
3295
3296 // Wrap another SPFCanvas around the surface
3297 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3298 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3299 depthMapCanvas->setShadowParams(params);
3300
3301 // set the depth map canvas to have the light we're drawing.
3302 SkLights::Builder builder;
3303 builder.add(fLights->light(i));
3304 sk_sp<SkLights> curLight = builder.finish();
3305 depthMapCanvas->setLights(std::move(curLight));
3306
3307 depthMapCanvas->drawPicture(picture);
3308 depthMap = surf->makeImageSnapshot();
3309 }
3310
3311 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3312 fLights->light(i).setShadowMap(std::move(depthMap));
3313 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3314 // we blur the variance map
3315 SkPaint blurPaint;
3316 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3317 params.fShadowRadius, nullptr));
3318
3319 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3320 kBGRA_8888_SkColorType,
3321 kOpaque_SkAlphaType);
3322
3323 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3324
3325 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3326
3327 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3328 }
3329 }
3330
3331 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003332 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3333 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003334 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003335 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003336 diffuseMap->height(),
3337 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003338
3339 shadowPaint.setShader(shadowShader);
3340
3341 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003342}
3343#endif
3344
reed@android.com8a1c16f2008-12-17 15:59:43 +00003345///////////////////////////////////////////////////////////////////////////////
3346///////////////////////////////////////////////////////////////////////////////
3347
reed3aafe112016-08-18 12:45:34 -07003348SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003349 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003350
3351 SkASSERT(canvas);
3352
reed3aafe112016-08-18 12:45:34 -07003353 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003354 fDone = !fImpl->next();
3355}
3356
3357SkCanvas::LayerIter::~LayerIter() {
3358 fImpl->~SkDrawIter();
3359}
3360
3361void SkCanvas::LayerIter::next() {
3362 fDone = !fImpl->next();
3363}
3364
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003365SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003366 return fImpl->getDevice();
3367}
3368
3369const SkMatrix& SkCanvas::LayerIter::matrix() const {
3370 return fImpl->getMatrix();
3371}
3372
3373const SkPaint& SkCanvas::LayerIter::paint() const {
3374 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003375 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003376 paint = &fDefaultPaint;
3377 }
3378 return *paint;
3379}
3380
reed1e7f5e72016-04-27 07:49:17 -07003381const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003382int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3383int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003384
3385///////////////////////////////////////////////////////////////////////////////
3386
fmalitac3b589a2014-06-05 12:40:07 -07003387SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003388
3389///////////////////////////////////////////////////////////////////////////////
3390
3391static bool supported_for_raster_canvas(const SkImageInfo& info) {
3392 switch (info.alphaType()) {
3393 case kPremul_SkAlphaType:
3394 case kOpaque_SkAlphaType:
3395 break;
3396 default:
3397 return false;
3398 }
3399
3400 switch (info.colorType()) {
3401 case kAlpha_8_SkColorType:
3402 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003403 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003404 break;
3405 default:
3406 return false;
3407 }
3408
3409 return true;
3410}
3411
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003412SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3413 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003414 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003415 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003416
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003417 SkBitmap bitmap;
3418 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003419 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003420 }
halcanary385fe4d2015-08-26 13:07:48 -07003421 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003422}
reedd5fa1a42014-08-09 11:08:05 -07003423
3424///////////////////////////////////////////////////////////////////////////////
3425
3426SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003427 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003428 : fCanvas(canvas)
3429 , fSaveCount(canvas->getSaveCount())
3430{
bsalomon49f085d2014-09-05 13:34:00 -07003431 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003432 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003433 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003434 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003435 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003436 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003437 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003438 canvas->save();
3439 }
mtklein6cfa73a2014-08-13 13:33:49 -07003440
bsalomon49f085d2014-09-05 13:34:00 -07003441 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003442 canvas->concat(*matrix);
3443 }
3444}
3445
3446SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3447 fCanvas->restoreToCount(fSaveCount);
3448}
reede8f30622016-03-23 18:59:25 -07003449
3450#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3451SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
3452 return this->makeSurface(info, props).release();
3453}
3454#endif
reed73603f32016-09-20 08:42:38 -07003455
3456/////////////////////////////////
3457
3458const SkCanvas::ClipOp SkCanvas::kDifference_Op;
3459const SkCanvas::ClipOp SkCanvas::kIntersect_Op;
3460const SkCanvas::ClipOp SkCanvas::kUnion_Op;
3461const SkCanvas::ClipOp SkCanvas::kXOR_Op;
3462const SkCanvas::ClipOp SkCanvas::kReverseDifference_Op;
3463const SkCanvas::ClipOp SkCanvas::kReplace_Op;
3464
3465static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3466static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3467static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3468static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3469static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3470static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");