blob: e3374dde52016b2bbccbbbc1458395c2198192b3 [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"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080018#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070019#include "SkImageFilter.h"
20#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070021#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060022#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050025#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070026#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070027#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070028#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000029#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070030#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000031#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050032#include "SkRasterHandleAllocator.h"
reed96472de2014-12-10 09:53:42 -080033#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070035#include "SkShadowPaintFilterCanvas.h"
36#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000037#include "SkSmallAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080038#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000039#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070040#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000041#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000042#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080043#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070044#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000045
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000046#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080047#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070049#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070050
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050052#include "SkClipOpPriv.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
55
reedc83a2972015-07-16 07:40:45 -070056/*
57 * Return true if the drawing this rect would hit every pixels in the canvas.
58 *
59 * Returns false if
60 * - rect does not contain the canvas' bounds
61 * - paint is not fill
62 * - paint would blur or otherwise change the coverage of the rect
63 */
64bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
65 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070066 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
67 (int)kNone_ShaderOverrideOpacity,
68 "need_matching_enums0");
69 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
70 (int)kOpaque_ShaderOverrideOpacity,
71 "need_matching_enums1");
72 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
73 (int)kNotOpaque_ShaderOverrideOpacity,
74 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070075
76 const SkISize size = this->getBaseLayerSize();
77 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
78 if (!this->getClipStack()->quickContains(bounds)) {
79 return false;
80 }
81
82 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070083 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070084 return false; // conservative
85 }
halcanaryc5769b22016-08-10 07:13:21 -070086
87 SkRect devRect;
88 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
89 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070090 return false;
91 }
92 }
93
94 if (paint) {
95 SkPaint::Style paintStyle = paint->getStyle();
96 if (!(paintStyle == SkPaint::kFill_Style ||
97 paintStyle == SkPaint::kStrokeAndFill_Style)) {
98 return false;
99 }
100 if (paint->getMaskFilter() || paint->getLooper()
101 || paint->getPathEffect() || paint->getImageFilter()) {
102 return false; // conservative
103 }
104 }
105 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
106}
107
108///////////////////////////////////////////////////////////////////////////////////////////////////
109
reedd990e2f2014-12-22 11:58:30 -0800110static bool gIgnoreSaveLayerBounds;
111void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
112 gIgnoreSaveLayerBounds = ignore;
113}
114bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
115 return gIgnoreSaveLayerBounds;
116}
117
reed0acf1b42014-12-22 16:12:38 -0800118static bool gTreatSpriteAsBitmap;
119void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
120 gTreatSpriteAsBitmap = spriteAsBitmap;
121}
122bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
123 return gTreatSpriteAsBitmap;
124}
125
reed@google.comda17f752012-08-16 18:27:05 +0000126// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127//#define SK_TRACE_SAVERESTORE
128
129#ifdef SK_TRACE_SAVERESTORE
130 static int gLayerCounter;
131 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
132 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
133
134 static int gRecCounter;
135 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
136 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
137
138 static int gCanvasCounter;
139 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
140 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
141#else
142 #define inc_layer()
143 #define dec_layer()
144 #define inc_rec()
145 #define dec_rec()
146 #define inc_canvas()
147 #define dec_canvas()
148#endif
149
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000150typedef SkTLazy<SkPaint> SkLazyPaint;
151
reedc83a2972015-07-16 07:40:45 -0700152void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000153 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700154 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
155 ? SkSurface::kDiscard_ContentChangeMode
156 : SkSurface::kRetain_ContentChangeMode);
157 }
158}
159
160void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
161 ShaderOverrideOpacity overrideOpacity) {
162 if (fSurfaceBase) {
163 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
164 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
165 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
166 // and therefore we don't care which mode we're in.
167 //
168 if (fSurfaceBase->outstandingImageSnapshot()) {
169 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
170 mode = SkSurface::kDiscard_ContentChangeMode;
171 }
172 }
173 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000174 }
175}
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000179/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 The clip/matrix/proc are fields that reflect the top of the save/restore
181 stack. Whenever the canvas changes, it marks a dirty flag, and then before
182 these are used (assuming we're not on a layer) we rebuild these cache
183 values: they reflect the top of the save stack, but translated and clipped
184 by the device's XY offset and bitmap-bounds.
185*/
186struct DeviceCM {
187 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000188 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000189 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000190 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700191 const SkMatrix* fMatrix;
192 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700193 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194
reed96e657d2015-03-10 17:30:07 -0700195 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700196 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700197 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700198 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700200 {
reed2c9e2002016-07-25 08:05:22 -0700201 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000202 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700203 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000206 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700207 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700208 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000209 }
reed@google.com4b226022011-01-11 18:32:13 +0000210
mtkleinfeaadee2015-04-08 11:25:48 -0700211 void reset(const SkIRect& bounds) {
212 SkASSERT(!fPaint);
213 SkASSERT(!fNext);
214 SkASSERT(fDevice);
215 fClip.setRect(bounds);
216 }
217
reed@google.com045e62d2011-10-24 12:19:46 +0000218 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700219 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000220 int x = fDevice->getOrigin().x();
221 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 int width = fDevice->width();
223 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000224
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 if ((x | y) == 0) {
226 fMatrix = &totalMatrix;
227 fClip = totalClip;
228 } else {
229 fMatrixStorage = totalMatrix;
230 fMatrixStorage.postTranslate(SkIntToScalar(-x),
231 SkIntToScalar(-y));
232 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 totalClip.translate(-x, -y, &fClip);
235 }
236
reed@google.com045e62d2011-10-24 12:19:46 +0000237 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238
239 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000242 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 SkRegion::kDifference_Op);
244 }
reed@google.com4b226022011-01-11 18:32:13 +0000245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246#ifdef SK_DEBUG
247 if (!fClip.isEmpty()) {
248 SkIRect deviceR;
249 deviceR.set(0, 0, width, height);
250 SkASSERT(deviceR.contains(fClip.getBounds()));
251 }
252#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000253 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254};
255
256/* This is the record we keep for each save/restore level in the stack.
257 Since a level optionally copies the matrix and/or stack, we have pointers
258 for these fields. If the value is copied for this level, the copy is
259 stored in the ...Storage field, and the pointer points to that. If the
260 value is not copied for this level, we ignore ...Storage, and just point
261 at the corresponding value in the previous level in the stack.
262*/
263class SkCanvas::MCRec {
264public:
reed1f836ee2014-07-07 07:49:34 -0700265 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700266 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 /* If there are any layers in the stack, this points to the top-most
268 one that is at or below this level in the stack (so we know what
269 bitmap/device to draw into from this level. This value is NOT
270 reference counted, since the real owner is either our fLayer field,
271 or a previous one in a lower level.)
272 */
reed2ff1fce2014-12-11 07:07:37 -0800273 DeviceCM* fTopLayer;
274 SkRasterClip fRasterClip;
275 SkMatrix fMatrix;
276 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277
vjiaoblacke5de1302016-07-13 14:05:28 -0700278 // This is the current cumulative depth (aggregate of all done translateZ calls)
279 SkScalar fCurDrawDepth;
280
reedd9544982014-09-09 18:46:22 -0700281 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700282 fFilter = nullptr;
283 fLayer = nullptr;
284 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800285 fMatrix.reset();
286 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700287 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700288
reedd9544982014-09-09 18:46:22 -0700289 // don't bother initializing fNext
290 inc_rec();
291 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700292 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
293 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700294 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700295 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700296 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800297 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700298
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299 // don't bother initializing fNext
300 inc_rec();
301 }
302 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000303 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700304 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305 dec_rec();
306 }
mtkleinfeaadee2015-04-08 11:25:48 -0700307
308 void reset(const SkIRect& bounds) {
309 SkASSERT(fLayer);
310 SkASSERT(fDeferredSaveCount == 0);
311
312 fMatrix.reset();
313 fRasterClip.setRect(bounds);
314 fLayer->reset(bounds);
315 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316};
317
reed02f9ed72016-09-06 09:06:18 -0700318static SkIRect compute_device_bounds(SkBaseDevice* device) {
319 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
320 device->width(), device->height());
321}
322
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323class SkDrawIter : public SkDraw {
324public:
reed3aafe112016-08-18 12:45:34 -0700325 SkDrawIter(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326 canvas->updateDeviceCMCache();
327
bungeman6bd52842016-10-27 09:30:08 -0700328 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700330
331 fMultiDeviceCS = nullptr;
332 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700333 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700334 fMultiDeviceCS->save();
335 }
336 }
337
338 ~SkDrawIter() {
339 if (fMultiDeviceCS) {
340 fMultiDeviceCS->restore();
341 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 }
reed@google.com4b226022011-01-11 18:32:13 +0000343
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700345 if (fMultiDeviceCS && fDevice) {
346 // remove the previous device's bounds
Mike Reedc1f77742016-12-09 09:00:50 -0500347 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), kDifference_SkClipOp);
reed02f9ed72016-09-06 09:06:18 -0700348 }
349
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700351 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
352 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 }
354
reed@google.comf68c5e22012-02-24 16:38:58 +0000355 const DeviceCM* rec = fCurrLayer;
356 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357
358 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000359 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700361 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700362 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700363 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000365 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366
367 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700368 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000369
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 return true;
371 }
372 return false;
373 }
reed@google.com4b226022011-01-11 18:32:13 +0000374
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000375 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700376 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000377 int getX() const { return fDevice->getOrigin().x(); }
378 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000381
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383 const DeviceCM* fCurrLayer;
384 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700385 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000386
387 typedef SkDraw INHERITED;
388};
389
390/////////////////////////////////////////////////////////////////////////////
391
reeddbc3cef2015-04-29 12:18:57 -0700392static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
393 return lazy->isValid() ? lazy->get() : lazy->set(orig);
394}
395
396/**
397 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700398 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700399 */
reedd053ce92016-03-22 10:17:23 -0700400static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700401 SkImageFilter* imgf = paint.getImageFilter();
402 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700403 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700404 }
405
reedd053ce92016-03-22 10:17:23 -0700406 SkColorFilter* imgCFPtr;
407 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700408 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700409 }
reedd053ce92016-03-22 10:17:23 -0700410 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700411
412 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700413 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700414 // there is no existing paint colorfilter, so we can just return the imagefilter's
415 return imgCF;
416 }
417
418 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
419 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700420 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700421}
422
senorblanco87e066e2015-10-28 11:23:36 -0700423/**
424 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
425 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
426 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
427 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
428 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
429 * conservative "effective" bounds based on the settings in the paint... with one exception. This
430 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
431 * deliberately ignored.
432 */
433static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
434 const SkRect& rawBounds,
435 SkRect* storage) {
436 SkPaint tmpUnfiltered(paint);
437 tmpUnfiltered.setImageFilter(nullptr);
438 if (tmpUnfiltered.canComputeFastBounds()) {
439 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
440 } else {
441 return rawBounds;
442 }
443}
444
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445class AutoDrawLooper {
446public:
senorblanco87e066e2015-10-28 11:23:36 -0700447 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
448 // paint. It's used to determine the size of the offscreen layer for filters.
449 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700450 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700451 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000452 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800453#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800455#else
456 fFilter = nullptr;
457#endif
reed4a8126e2014-09-22 07:29:03 -0700458 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000459 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700460 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000461 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000462
reedd053ce92016-03-22 10:17:23 -0700463 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700464 if (simplifiedCF) {
465 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700466 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700467 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700468 fPaint = paint;
469 }
470
471 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700472 /**
473 * We implement ImageFilters for a given draw by creating a layer, then applying the
474 * imagefilter to the pixels of that layer (its backing surface/image), and then
475 * we call restore() to xfer that layer to the main canvas.
476 *
477 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
478 * 2. Generate the src pixels:
479 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
480 * return (fPaint). We then draw the primitive (using srcover) into a cleared
481 * buffer/surface.
482 * 3. Restore the layer created in #1
483 * The imagefilter is passed the buffer/surface from the layer (now filled with the
484 * src pixels of the primitive). It returns a new "filtered" buffer, which we
485 * draw onto the previous layer using the xfermode from the original paint.
486 */
reed@google.com8926b162012-03-23 15:36:36 +0000487 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500488 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700489 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700490 SkRect storage;
491 if (rawBounds) {
492 // Make rawBounds include all paint outsets except for those due to image filters.
493 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
494 }
reedbfd5f172016-01-07 11:28:08 -0800495 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700496 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700497 fTempLayerForImageFilter = true;
498 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000499 }
500
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000501 if (SkDrawLooper* looper = paint.getLooper()) {
herbbf6d80a2016-11-15 06:26:56 -0800502 fLooperContext = fLooperContextAllocator.createWithIniter(
503 looper->contextSize(),
504 [&](void* buffer) {
505 return looper->createContext(canvas, buffer);
506 });
reed@google.com129ec222012-05-15 13:24:09 +0000507 fIsSimple = false;
508 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700509 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000510 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700511 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000512 }
513 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000514
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700516 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000517 fCanvas->internalRestore();
518 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000519 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000521
reed@google.com4e2b3d32011-04-07 14:18:59 +0000522 const SkPaint& paint() const {
523 SkASSERT(fPaint);
524 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000526
reed@google.com129ec222012-05-15 13:24:09 +0000527 bool next(SkDrawFilter::Type drawType) {
528 if (fDone) {
529 return false;
530 } else if (fIsSimple) {
531 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000532 return !fPaint->nothingToDraw();
533 } else {
534 return this->doNext(drawType);
535 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000536 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000537
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538private:
reeddbc3cef2015-04-29 12:18:57 -0700539 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
540 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000541 SkCanvas* fCanvas;
542 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000543 SkDrawFilter* fFilter;
544 const SkPaint* fPaint;
545 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700546 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000547 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000548 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000549 SkDrawLooper::Context* fLooperContext;
550 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000551
552 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553};
554
reed@google.com129ec222012-05-15 13:24:09 +0000555bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700556 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000557 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700558 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000559
reeddbc3cef2015-04-29 12:18:57 -0700560 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
561 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000562
reed5c476fb2015-04-20 08:04:21 -0700563 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700564 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700565 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000566 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000567
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000568 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000569 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000570 return false;
571 }
572 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000573 if (!fFilter->filter(paint, drawType)) {
574 fDone = true;
575 return false;
576 }
halcanary96fcdcc2015-08-27 07:41:13 -0700577 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000578 // no looper means we only draw once
579 fDone = true;
580 }
581 }
582 fPaint = paint;
583
584 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000585 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000586 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000587 }
588
589 // call this after any possible paint modifiers
590 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700591 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000592 return false;
593 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000594 return true;
595}
596
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597////////// macros to place around the internal draw calls //////////////////
598
reed3aafe112016-08-18 12:45:34 -0700599#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
600 this->predrawNotify(); \
601 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
602 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800603 SkDrawIter iter(this);
604
605
reed@google.com8926b162012-03-23 15:36:36 +0000606#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000607 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700608 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000609 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000610 SkDrawIter iter(this);
611
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000612#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000613 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700614 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000615 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000616 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000617
reedc83a2972015-07-16 07:40:45 -0700618#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
619 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700620 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700621 while (looper.next(type)) { \
622 SkDrawIter iter(this);
623
reed@google.com4e2b3d32011-04-07 14:18:59 +0000624#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625
626////////////////////////////////////////////////////////////////////////////
627
msarettfbfa2582016-08-12 08:29:08 -0700628static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
629 if (bounds.isEmpty()) {
630 return SkRect::MakeEmpty();
631 }
632
633 // Expand bounds out by 1 in case we are anti-aliasing. We store the
634 // bounds as floats to enable a faster quick reject implementation.
635 SkRect dst;
636 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
637 return dst;
638}
639
mtkleinfeaadee2015-04-08 11:25:48 -0700640void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
641 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700642 fClipStack->reset();
643 fMCRec->reset(bounds);
644
645 // We're peering through a lot of structs here. Only at this scope do we
646 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
647 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700648 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700649 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700650}
651
reedd9544982014-09-09 18:46:22 -0700652SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800653 if (device && device->forceConservativeRasterClip()) {
654 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
655 }
656 // Since init() is only called once by our constructors, it is safe to perform this
657 // const-cast.
658 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
659
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000660 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700661 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800662 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700663 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700664#ifdef SK_EXPERIMENTAL_SHADOWING
665 fLights = nullptr;
666#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667
halcanary385fe4d2015-08-26 13:07:48 -0700668 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700669
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700671 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500672 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700673 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674
reeda499f902015-05-01 09:34:31 -0700675 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
676 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700677 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700678 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700679
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681
halcanary96fcdcc2015-08-27 07:41:13 -0700682 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000683
reedf92c8662014-08-18 08:02:43 -0700684 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700685 // The root device and the canvas should always have the same pixel geometry
686 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700687 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800688 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700689 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700690 }
msarettfbfa2582016-08-12 08:29:08 -0700691
reedf92c8662014-08-18 08:02:43 -0700692 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693}
694
reed@google.comcde92112011-07-06 20:00:52 +0000695SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000696 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700697 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800698 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000699{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000700 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000701
halcanary96fcdcc2015-08-27 07:41:13 -0700702 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000703}
704
reedd9544982014-09-09 18:46:22 -0700705static SkBitmap make_nopixels(int width, int height) {
706 SkBitmap bitmap;
707 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
708 return bitmap;
709}
710
711class SkNoPixelsBitmapDevice : public SkBitmapDevice {
712public:
robertphillipsfcf78292015-06-19 11:49:52 -0700713 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
714 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800715 {
716 this->setOrigin(bounds.x(), bounds.y());
717 }
reedd9544982014-09-09 18:46:22 -0700718
719private:
piotaixrb5fae932014-09-24 13:03:30 -0700720
reedd9544982014-09-09 18:46:22 -0700721 typedef SkBitmapDevice INHERITED;
722};
723
reed96a857e2015-01-25 10:33:58 -0800724SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000725 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800726 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800727 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000728{
729 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700730
halcanary385fe4d2015-08-26 13:07:48 -0700731 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
732 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700733}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000734
reed78e27682014-11-19 08:04:34 -0800735SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700736 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700737 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800738 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700739{
740 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700741
halcanary385fe4d2015-08-26 13:07:48 -0700742 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700743}
744
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000745SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000746 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700747 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800748 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000749{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700751
reedd9544982014-09-09 18:46:22 -0700752 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753}
754
robertphillipsfcf78292015-06-19 11:49:52 -0700755SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
756 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700757 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800758 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700759{
760 inc_canvas();
761
762 this->init(device, flags);
763}
764
reed4a8126e2014-09-22 07:29:03 -0700765SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700766 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700767 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800768 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700769{
770 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700771
Hal Canary704cd322016-11-07 14:13:52 -0500772 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
773 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700774}
reed29c857d2014-09-21 10:25:07 -0700775
Mike Reed356f7c22017-01-10 11:58:39 -0500776SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
777 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700778 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
779 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500780 , fAllocator(std::move(alloc))
reed42b73eb2015-11-20 13:42:42 -0800781 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700782{
783 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700784
Mike Reed356f7c22017-01-10 11:58:39 -0500785 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500786 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787}
788
Mike Reed356f7c22017-01-10 11:58:39 -0500789SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
790
reed@android.com8a1c16f2008-12-17 15:59:43 +0000791SkCanvas::~SkCanvas() {
792 // free up the contents of our deque
793 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000794
reed@android.com8a1c16f2008-12-17 15:59:43 +0000795 this->internalRestore(); // restore the last, since we're going away
796
halcanary385fe4d2015-08-26 13:07:48 -0700797 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000798
reed@android.com8a1c16f2008-12-17 15:59:43 +0000799 dec_canvas();
800}
801
fmalita53d9f1c2016-01-25 06:23:54 -0800802#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000803SkDrawFilter* SkCanvas::getDrawFilter() const {
804 return fMCRec->fFilter;
805}
806
807SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700808 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
810 return filter;
811}
fmalita77650002016-01-21 18:47:11 -0800812#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000814SkMetaData& SkCanvas::getMetaData() {
815 // metadata users are rare, so we lazily allocate it. If that changes we
816 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700817 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000818 fMetaData = new SkMetaData;
819 }
820 return *fMetaData;
821}
822
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823///////////////////////////////////////////////////////////////////////////////
824
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000825void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700826 this->onFlush();
827}
828
829void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000830 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000831 if (device) {
832 device->flush();
833 }
834}
835
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000836SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000837 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000838 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
839}
840
senorblancoafc7cce2016-02-02 18:44:15 -0800841SkIRect SkCanvas::getTopLayerBounds() const {
842 SkBaseDevice* d = this->getTopDevice();
843 if (!d) {
844 return SkIRect::MakeEmpty();
845 }
846 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
847}
848
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000849SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000851 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000852 SkASSERT(rec && rec->fLayer);
853 return rec->fLayer->fDevice;
854}
855
Florin Malita0ed3b642017-01-13 16:56:38 +0000856SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000857 return fMCRec->fTopLayer->fDevice;
858}
859
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000860bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700861 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000862 return false;
863 }
864
865 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700866 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700867 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000868 return false;
869 }
870 weAllocated = true;
871 }
872
reedcf01e312015-05-23 19:14:51 -0700873 SkAutoPixmapUnlock unlocker;
874 if (bitmap->requestLock(&unlocker)) {
875 const SkPixmap& pm = unlocker.pixmap();
876 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
877 return true;
878 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000879 }
880
881 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500882 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000883 }
884 return false;
885}
reed@google.com51df9e32010-12-23 19:29:18 +0000886
bsalomon@google.comc6980972011-11-02 19:57:21 +0000887bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000888 SkIRect r = srcRect;
889 const SkISize size = this->getBaseLayerSize();
890 if (!r.intersect(0, 0, size.width(), size.height())) {
891 bitmap->reset();
892 return false;
893 }
894
reed84825042014-09-02 12:50:45 -0700895 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000896 // bitmap will already be reset.
897 return false;
898 }
899 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
900 bitmap->reset();
901 return false;
902 }
903 return true;
904}
905
reed96472de2014-12-10 09:53:42 -0800906bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000907 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000908 if (!device) {
909 return false;
910 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000911 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800912
reed96472de2014-12-10 09:53:42 -0800913 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
914 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000915 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000916 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000917
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000918 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800919 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000920}
921
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000922bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700923 SkAutoPixmapUnlock unlocker;
924 if (bitmap.requestLock(&unlocker)) {
925 const SkPixmap& pm = unlocker.pixmap();
926 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000927 }
928 return false;
929}
930
931bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
932 int x, int y) {
933 switch (origInfo.colorType()) {
934 case kUnknown_SkColorType:
935 case kIndex_8_SkColorType:
936 return false;
937 default:
938 break;
939 }
halcanary96fcdcc2015-08-27 07:41:13 -0700940 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000941 return false;
942 }
943
944 const SkISize size = this->getBaseLayerSize();
945 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
946 if (!target.intersect(0, 0, size.width(), size.height())) {
947 return false;
948 }
949
950 SkBaseDevice* device = this->getDevice();
951 if (!device) {
952 return false;
953 }
954
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000955 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700956 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000957
958 // if x or y are negative, then we have to adjust pixels
959 if (x > 0) {
960 x = 0;
961 }
962 if (y > 0) {
963 y = 0;
964 }
965 // here x,y are either 0 or negative
966 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
967
reed4af35f32014-06-27 17:47:49 -0700968 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700969 const bool completeOverwrite = info.dimensions() == size;
970 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700971
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000972 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000973 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000974}
reed@google.com51df9e32010-12-23 19:29:18 +0000975
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976//////////////////////////////////////////////////////////////////////////////
977
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978void SkCanvas::updateDeviceCMCache() {
979 if (fDeviceCMDirty) {
980 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700981 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000983
halcanary96fcdcc2015-08-27 07:41:13 -0700984 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700985 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000987 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988 do {
reedde6c5312016-09-02 12:10:07 -0700989 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700990 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991 }
992 fDeviceCMDirty = false;
993 }
994}
995
reed@android.com8a1c16f2008-12-17 15:59:43 +0000996///////////////////////////////////////////////////////////////////////////////
997
reed2ff1fce2014-12-11 07:07:37 -0800998void SkCanvas::checkForDeferredSave() {
999 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -08001000 this->doSave();
1001 }
1002}
1003
reedf0090cb2014-11-26 08:55:51 -08001004int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -08001005#ifdef SK_DEBUG
1006 int count = 0;
1007 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1008 for (;;) {
1009 const MCRec* rec = (const MCRec*)iter.next();
1010 if (!rec) {
1011 break;
1012 }
1013 count += 1 + rec->fDeferredSaveCount;
1014 }
1015 SkASSERT(count == fSaveCount);
1016#endif
1017 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001018}
1019
1020int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001021 fSaveCount += 1;
1022 fMCRec->fDeferredSaveCount += 1;
1023 return this->getSaveCount() - 1; // return our prev value
1024}
1025
1026void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001027 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001028
1029 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1030 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001031 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001032}
1033
1034void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001035 if (fMCRec->fDeferredSaveCount > 0) {
1036 SkASSERT(fSaveCount > 1);
1037 fSaveCount -= 1;
1038 fMCRec->fDeferredSaveCount -= 1;
1039 } else {
1040 // check for underflow
1041 if (fMCStack.count() > 1) {
1042 this->willRestore();
1043 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001044 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001045 this->internalRestore();
1046 this->didRestore();
1047 }
reedf0090cb2014-11-26 08:55:51 -08001048 }
1049}
1050
1051void SkCanvas::restoreToCount(int count) {
1052 // sanity check
1053 if (count < 1) {
1054 count = 1;
1055 }
mtkleinf0f14112014-12-12 08:46:25 -08001056
reedf0090cb2014-11-26 08:55:51 -08001057 int n = this->getSaveCount() - count;
1058 for (int i = 0; i < n; ++i) {
1059 this->restore();
1060 }
1061}
1062
reed2ff1fce2014-12-11 07:07:37 -08001063void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001065 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001066 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001067
reed687fa1c2015-04-07 08:00:56 -07001068 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069}
1070
reed4960eee2015-12-18 07:09:18 -08001071bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001072 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073}
1074
reed4960eee2015-12-18 07:09:18 -08001075bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001076 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001077 SkIRect clipBounds;
1078 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001079 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001080 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001081
reed96e657d2015-03-10 17:30:07 -07001082 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1083
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001084 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001085 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001086 if (bounds && !imageFilter->canComputeFastBounds()) {
1087 bounds = nullptr;
1088 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001089 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001090 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001091 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001092 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001093
reed96e657d2015-03-10 17:30:07 -07001094 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095 r.roundOut(&ir);
1096 // early exit if the layer's bounds are clipped out
1097 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001098 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001099 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001100 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001101 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001102 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103 }
1104 } else { // no user bounds, so just use the clip
1105 ir = clipBounds;
1106 }
reed180aec42015-03-11 10:39:04 -07001107 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108
reed4960eee2015-12-18 07:09:18 -08001109 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001110 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001111 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001112 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001113 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001114 }
1115
1116 if (intersection) {
1117 *intersection = ir;
1118 }
1119 return true;
1120}
1121
reed4960eee2015-12-18 07:09:18 -08001122
reed4960eee2015-12-18 07:09:18 -08001123int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1124 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001125}
1126
reed70ee31b2015-12-10 13:44:45 -08001127int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001128 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1129}
1130
1131int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1132 SaveLayerRec rec(origRec);
1133 if (gIgnoreSaveLayerBounds) {
1134 rec.fBounds = nullptr;
1135 }
1136 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1137 fSaveCount += 1;
1138 this->internalSaveLayer(rec, strategy);
1139 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001140}
1141
reeda2217ef2016-07-20 06:04:34 -07001142void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1143 SkBaseDevice* dst, const SkMatrix& ctm,
1144 const SkClipStack* clipStack) {
1145 SkDraw draw;
1146 SkRasterClip rc;
1147 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1148 if (!dst->accessPixels(&draw.fDst)) {
1149 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001150 }
reeda2217ef2016-07-20 06:04:34 -07001151 draw.fMatrix = &SkMatrix::I();
1152 draw.fRC = &rc;
1153 draw.fClipStack = clipStack;
1154 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001155
1156 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001157 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001158
1159 int x = src->getOrigin().x() - dst->getOrigin().x();
1160 int y = src->getOrigin().y() - dst->getOrigin().y();
1161 auto special = src->snapSpecial();
1162 if (special) {
1163 dst->drawSpecial(draw, special.get(), x, y, p);
1164 }
robertphillips7354a4b2015-12-16 05:08:27 -08001165}
reed70ee31b2015-12-10 13:44:45 -08001166
reed129ed1c2016-02-22 06:42:31 -08001167static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1168 const SkPaint* paint) {
1169 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1170 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001171 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001172 const bool hasImageFilter = paint && paint->getImageFilter();
1173
1174 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1175 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1176 // force to L32
1177 return SkImageInfo::MakeN32(w, h, alphaType);
1178 } else {
1179 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001180 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001181 }
1182}
1183
reed4960eee2015-12-18 07:09:18 -08001184void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1185 const SkRect* bounds = rec.fBounds;
1186 const SkPaint* paint = rec.fPaint;
1187 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1188
reed8c30a812016-04-20 16:36:51 -07001189 SkLazyPaint lazyP;
1190 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1191 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001192 SkMatrix remainder;
1193 SkSize scale;
1194 /*
1195 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1196 * but they do handle scaling. To accommodate this, we do the following:
1197 *
1198 * 1. Stash off the current CTM
1199 * 2. Decompose the CTM into SCALE and REMAINDER
1200 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1201 * contains the REMAINDER
1202 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1203 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1204 * of the original imagefilter, and draw that (via drawSprite)
1205 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1206 *
1207 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1208 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1209 */
reed96a04f32016-04-25 09:25:15 -07001210 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001211 stashedMatrix.decomposeScale(&scale, &remainder))
1212 {
1213 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1214 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1215 SkPaint* p = lazyP.set(*paint);
1216 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1217 SkFilterQuality::kLow_SkFilterQuality,
1218 sk_ref_sp(imageFilter)));
1219 imageFilter = p->getImageFilter();
1220 paint = p;
1221 }
reed8c30a812016-04-20 16:36:51 -07001222
junov@chromium.orga907ac32012-02-24 21:54:07 +00001223 // do this before we create the layer. We don't call the public save() since
1224 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001225 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001226
1227 fDeviceCMDirty = true;
1228
1229 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001230 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001231 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001232 }
1233
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001234 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1235 // the clipRectBounds() call above?
1236 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001237 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001238 }
1239
reed4960eee2015-12-18 07:09:18 -08001240 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001241 SkPixelGeometry geo = fProps.pixelGeometry();
1242 if (paint) {
reed76033be2015-03-14 10:54:31 -07001243 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001244 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001245 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001246 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001247 }
1248 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249
robertphillips5139e502016-07-19 05:10:40 -07001250 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001251 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001252 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001253 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001254 }
reedb2db8982014-11-13 12:41:02 -08001255
robertphillips5139e502016-07-19 05:10:40 -07001256 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001257 paint);
1258
Hal Canary704cd322016-11-07 14:13:52 -05001259 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001260 {
reed70ee31b2015-12-10 13:44:45 -08001261 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001262 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001263 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001264 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001265 preserveLCDText,
1266 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001267 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1268 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001269 return;
reed61f501f2015-04-29 08:34:00 -07001270 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001271 }
robertphillips5139e502016-07-19 05:10:40 -07001272 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001273
Hal Canary704cd322016-11-07 14:13:52 -05001274 DeviceCM* layer =
1275 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276
1277 layer->fNext = fMCRec->fTopLayer;
1278 fMCRec->fLayer = layer;
1279 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001280
1281 if (rec.fBackdrop) {
Hal Canary704cd322016-11-07 14:13:52 -05001282 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
reeda2217ef2016-07-20 06:04:34 -07001283 fMCRec->fMatrix, this->getClipStack());
1284 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285}
1286
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001287int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001288 if (0xFF == alpha) {
1289 return this->saveLayer(bounds, nullptr);
1290 } else {
1291 SkPaint tmpPaint;
1292 tmpPaint.setAlpha(alpha);
1293 return this->saveLayer(bounds, &tmpPaint);
1294 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001295}
1296
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297void SkCanvas::internalRestore() {
1298 SkASSERT(fMCStack.count() != 0);
1299
1300 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301
reed687fa1c2015-04-07 08:00:56 -07001302 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001303
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001304 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 DeviceCM* layer = fMCRec->fLayer; // may be null
1306 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001307 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308
1309 // now do the normal restore()
1310 fMCRec->~MCRec(); // balanced in save()
1311 fMCStack.pop_back();
1312 fMCRec = (MCRec*)fMCStack.back();
1313
1314 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1315 since if we're being recorded, we don't want to record this (the
1316 recorder will have already recorded the restore).
1317 */
bsalomon49f085d2014-09-05 13:34:00 -07001318 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001320 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001321 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001322 // restore what we smashed in internalSaveLayer
1323 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001324 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001326 delete layer;
reedb679ca82015-04-07 04:40:48 -07001327 } else {
1328 // we're at the root
reeda499f902015-05-01 09:34:31 -07001329 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001330 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001331 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001333 }
msarettfbfa2582016-08-12 08:29:08 -07001334
1335 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001336 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001337 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1338 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339}
1340
reede8f30622016-03-23 18:59:25 -07001341sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001342 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001343 props = &fProps;
1344 }
1345 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001346}
1347
reede8f30622016-03-23 18:59:25 -07001348sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001349 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001350 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001351}
1352
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001353SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001354 return this->onImageInfo();
1355}
1356
1357SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001358 SkBaseDevice* dev = this->getDevice();
1359 if (dev) {
1360 return dev->imageInfo();
1361 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001362 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001363 }
1364}
1365
brianosman898235c2016-04-06 07:38:23 -07001366bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001367 return this->onGetProps(props);
1368}
1369
1370bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001371 SkBaseDevice* dev = this->getDevice();
1372 if (dev) {
1373 if (props) {
1374 *props = fProps;
1375 }
1376 return true;
1377 } else {
1378 return false;
1379 }
1380}
1381
reed6ceeebd2016-03-09 14:26:26 -08001382bool SkCanvas::peekPixels(SkPixmap* pmap) {
1383 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001384}
1385
reed884e97c2015-05-26 11:31:54 -07001386bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001387 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001388 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001389}
1390
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001391void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001392 SkPixmap pmap;
1393 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001394 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001395 }
1396 if (info) {
1397 *info = pmap.info();
1398 }
1399 if (rowBytes) {
1400 *rowBytes = pmap.rowBytes();
1401 }
1402 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001403 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001404 }
reed884e97c2015-05-26 11:31:54 -07001405 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001406}
1407
reed884e97c2015-05-26 11:31:54 -07001408bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001409 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001410 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001411}
1412
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414
reed7503d602016-07-15 14:23:29 -07001415void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001417 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418 paint = &tmp;
1419 }
reed@google.com4b226022011-01-11 18:32:13 +00001420
reed@google.com8926b162012-03-23 15:36:36 +00001421 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001422
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001424 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001425 paint = &looper.paint();
1426 SkImageFilter* filter = paint->getImageFilter();
1427 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001428 if (filter) {
1429 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1430 if (specialImage) {
1431 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1432 }
reed@google.com76dd2772012-01-05 21:15:07 +00001433 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001434 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001435 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436 }
reeda2217ef2016-07-20 06:04:34 -07001437
reed@google.com4e2b3d32011-04-07 14:18:59 +00001438 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439}
1440
reed32704672015-12-16 08:27:10 -08001441/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001442
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001443void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001444 if (dx || dy) {
1445 this->checkForDeferredSave();
1446 fDeviceCMDirty = true;
1447 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001448
reedfe69b502016-09-12 06:31:48 -07001449 // Translate shouldn't affect the is-scale-translateness of the matrix.
1450 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001451
reedfe69b502016-09-12 06:31:48 -07001452 this->didTranslate(dx,dy);
1453 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454}
1455
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001456void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001457 SkMatrix m;
1458 m.setScale(sx, sy);
1459 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001460}
1461
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001462void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001463 SkMatrix m;
1464 m.setRotate(degrees);
1465 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466}
1467
bungeman7438bfc2016-07-12 15:01:19 -07001468void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1469 SkMatrix m;
1470 m.setRotate(degrees, px, py);
1471 this->concat(m);
1472}
1473
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001474void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001475 SkMatrix m;
1476 m.setSkew(sx, sy);
1477 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001478}
1479
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001480void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001481 if (matrix.isIdentity()) {
1482 return;
1483 }
1484
reed2ff1fce2014-12-11 07:07:37 -08001485 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001487 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001488 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001489 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001490}
1491
reed8c30a812016-04-20 16:36:51 -07001492void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001493 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001494 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001495 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001496}
1497
1498void SkCanvas::setMatrix(const SkMatrix& matrix) {
1499 this->checkForDeferredSave();
1500 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001501 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001502}
1503
reed@android.com8a1c16f2008-12-17 15:59:43 +00001504void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001505 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001506}
1507
vjiaoblack95302da2016-07-21 10:25:54 -07001508#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001509void SkCanvas::translateZ(SkScalar z) {
1510 this->checkForDeferredSave();
1511 this->fMCRec->fCurDrawDepth += z;
1512 this->didTranslateZ(z);
1513}
1514
1515SkScalar SkCanvas::getZ() const {
1516 return this->fMCRec->fCurDrawDepth;
1517}
1518
vjiaoblack95302da2016-07-21 10:25:54 -07001519void SkCanvas::setLights(sk_sp<SkLights> lights) {
1520 this->fLights = lights;
1521}
1522
1523sk_sp<SkLights> SkCanvas::getLights() const {
1524 return this->fLights;
1525}
1526#endif
1527
reed@android.com8a1c16f2008-12-17 15:59:43 +00001528//////////////////////////////////////////////////////////////////////////////
1529
Mike Reedc1f77742016-12-09 09:00:50 -05001530void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001531 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001532 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1533 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001534}
1535
Mike Reedc1f77742016-12-09 09:00:50 -05001536void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001537 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reedc64eff52015-11-21 12:39:45 -08001538 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001539 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1540 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1541 isAA);
reedc64eff52015-11-21 12:39:45 -08001542 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001543 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001544}
1545
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001546void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1547 fClipRestrictionRect = rect;
1548 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
1549 if (!fClipRestrictionRect.isEmpty()) {
1550 this->checkForDeferredSave();
1551 AutoValidateClip avc(this);
1552 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1553 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1554 fDeviceCMDirty = true;
1555 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1556 }
1557}
1558
Mike Reedc1f77742016-12-09 09:00:50 -05001559void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001560 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001561 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001562 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001563 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1564 } else {
1565 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001566 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001567}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001568
Mike Reedc1f77742016-12-09 09:00:50 -05001569void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001570 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001571
Brian Salomona3b45d42016-10-03 11:36:16 -04001572 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001573
Brian Salomona3b45d42016-10-03 11:36:16 -04001574 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1575 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1576 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1577 isAA);
1578 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1579 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001580}
1581
Mike Reedc1f77742016-12-09 09:00:50 -05001582void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001583 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001584 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001585
1586 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1587 SkRect r;
1588 if (path.isRect(&r)) {
1589 this->onClipRect(r, op, edgeStyle);
1590 return;
1591 }
1592 SkRRect rrect;
1593 if (path.isOval(&r)) {
1594 rrect.setOval(r);
1595 this->onClipRRect(rrect, op, edgeStyle);
1596 return;
1597 }
1598 if (path.isRRect(&rrect)) {
1599 this->onClipRRect(rrect, op, edgeStyle);
1600 return;
1601 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001602 }
robertphillips39f05382015-11-24 09:30:12 -08001603
1604 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001605}
1606
Mike Reedc1f77742016-12-09 09:00:50 -05001607void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001608 AutoValidateClip avc(this);
1609
reed@android.com8a1c16f2008-12-17 15:59:43 +00001610 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001611 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001612
Brian Salomona3b45d42016-10-03 11:36:16 -04001613 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614
Brian Salomona3b45d42016-10-03 11:36:16 -04001615 const SkPath* rasterClipPath = &path;
1616 const SkMatrix* matrix = &fMCRec->fMatrix;
1617 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001618 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001619 isAA = getClipStack()->asPath(&tempPath);
1620 rasterClipPath = &tempPath;
1621 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001622 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001623 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001624 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1625 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001626 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001627}
1628
Mike Reedc1f77742016-12-09 09:00:50 -05001629void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001630 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001631 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001632}
1633
Mike Reedc1f77742016-12-09 09:00:50 -05001634void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001635 AutoValidateClip avc(this);
1636
reed@android.com8a1c16f2008-12-17 15:59:43 +00001637 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001638
reed@google.com5c3d1472011-02-22 19:12:23 +00001639 // todo: signal fClipStack that we have a region, and therefore (I guess)
1640 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001641 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001642
reed73603f32016-09-20 08:42:38 -07001643 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001644 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001645}
1646
reed@google.com819c9212011-02-23 18:56:55 +00001647#ifdef SK_DEBUG
1648void SkCanvas::validateClip() const {
1649 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001650 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001651 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001652 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001653 return;
1654 }
1655
reed@google.com819c9212011-02-23 18:56:55 +00001656 SkIRect ir;
1657 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001658 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001659
reed687fa1c2015-04-07 08:00:56 -07001660 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001661 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001662 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001663 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001664 case SkClipStack::Element::kRect_Type:
1665 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001666 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001667 break;
1668 case SkClipStack::Element::kEmpty_Type:
1669 tmpClip.setEmpty();
1670 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001671 default: {
1672 SkPath path;
1673 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001674 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1675 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001676 break;
1677 }
reed@google.com819c9212011-02-23 18:56:55 +00001678 }
1679 }
reed@google.com819c9212011-02-23 18:56:55 +00001680}
1681#endif
1682
reed@google.com90c07ea2012-04-13 13:50:27 +00001683void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001684 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001685 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001686
halcanary96fcdcc2015-08-27 07:41:13 -07001687 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001688 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001689 }
1690}
1691
reed@google.com5c3d1472011-02-22 19:12:23 +00001692///////////////////////////////////////////////////////////////////////////////
1693
reed@google.com754de5f2014-02-24 19:38:20 +00001694bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001695 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001696}
1697
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001698bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001699 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001700}
1701
msarettfbfa2582016-08-12 08:29:08 -07001702static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1703#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1704 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1705 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1706 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1707 return 0xF != _mm_movemask_ps(mask);
1708#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1709 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1710 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1711 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1712 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1713#else
1714 SkRect devRectAsRect;
1715 SkRect devClipAsRect;
1716 devRect.store(&devRectAsRect.fLeft);
1717 devClip.store(&devClipAsRect.fLeft);
1718 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1719#endif
1720}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001721
msarettfbfa2582016-08-12 08:29:08 -07001722// It's important for this function to not be inlined. Otherwise the compiler will share code
1723// between the fast path and the slow path, resulting in two slow paths.
1724static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1725 const SkMatrix& matrix) {
1726 SkRect deviceRect;
1727 matrix.mapRect(&deviceRect, src);
1728 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1729}
1730
1731bool SkCanvas::quickReject(const SkRect& src) const {
1732#ifdef SK_DEBUG
1733 // Verify that fDeviceClipBounds are set properly.
1734 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001735 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001736 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001737 } else {
msarettfbfa2582016-08-12 08:29:08 -07001738 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739 }
msarettfbfa2582016-08-12 08:29:08 -07001740
msarett9637ea92016-08-18 14:03:30 -07001741 // Verify that fIsScaleTranslate is set properly.
1742 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001743#endif
1744
msarett9637ea92016-08-18 14:03:30 -07001745 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001746 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1747 }
1748
1749 // We inline the implementation of mapScaleTranslate() for the fast path.
1750 float sx = fMCRec->fMatrix.getScaleX();
1751 float sy = fMCRec->fMatrix.getScaleY();
1752 float tx = fMCRec->fMatrix.getTranslateX();
1753 float ty = fMCRec->fMatrix.getTranslateY();
1754 Sk4f scale(sx, sy, sx, sy);
1755 Sk4f trans(tx, ty, tx, ty);
1756
1757 // Apply matrix.
1758 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1759
1760 // Make sure left < right, top < bottom.
1761 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1762 Sk4f min = Sk4f::Min(ltrb, rblt);
1763 Sk4f max = Sk4f::Max(ltrb, rblt);
1764 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1765 // ARM this sequence generates the fastest (a single instruction).
1766 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1767
1768 // Check if the device rect is NaN or outside the clip.
1769 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001770}
1771
reed@google.com3b3e8952012-08-16 20:53:31 +00001772bool SkCanvas::quickReject(const SkPath& path) const {
1773 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001774}
1775
reed@google.com3b3e8952012-08-16 20:53:31 +00001776bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001777 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001778 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001779 return false;
1780 }
1781
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001782 SkMatrix inverse;
1783 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001784 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001785 if (bounds) {
1786 bounds->setEmpty();
1787 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001788 return false;
1789 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001790
bsalomon49f085d2014-09-05 13:34:00 -07001791 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001792 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001793 // adjust it outwards in case we are antialiasing
1794 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001795
reed@google.com8f4d2302013-12-17 16:44:46 +00001796 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1797 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001798 inverse.mapRect(bounds, r);
1799 }
1800 return true;
1801}
1802
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001803bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001804 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001805 if (clip.isEmpty()) {
1806 if (bounds) {
1807 bounds->setEmpty();
1808 }
1809 return false;
1810 }
1811
bsalomon49f085d2014-09-05 13:34:00 -07001812 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001813 *bounds = clip.getBounds();
1814 }
1815 return true;
1816}
1817
reed@android.com8a1c16f2008-12-17 15:59:43 +00001818const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001819 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001820}
1821
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001822const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001823 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001824}
1825
Brian Osman11052242016-10-27 14:47:55 -04001826GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001827 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001828 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001829}
1830
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001831GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001832 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001833 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001834}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001835
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001836void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1837 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001838 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001839 if (outer.isEmpty()) {
1840 return;
1841 }
1842 if (inner.isEmpty()) {
1843 this->drawRRect(outer, paint);
1844 return;
1845 }
1846
1847 // We don't have this method (yet), but technically this is what we should
1848 // be able to assert...
1849 // SkASSERT(outer.contains(inner));
1850 //
1851 // For now at least check for containment of bounds
1852 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1853
1854 this->onDrawDRRect(outer, inner, paint);
1855}
1856
reed41af9662015-01-05 07:49:08 -08001857// These need to stop being virtual -- clients need to override the onDraw... versions
1858
1859void SkCanvas::drawPaint(const SkPaint& paint) {
1860 this->onDrawPaint(paint);
1861}
1862
1863void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1864 this->onDrawRect(r, paint);
1865}
1866
msarettdca352e2016-08-26 06:37:45 -07001867void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1868 if (region.isEmpty()) {
1869 return;
1870 }
1871
1872 if (region.isRect()) {
1873 return this->drawIRect(region.getBounds(), paint);
1874 }
1875
1876 this->onDrawRegion(region, paint);
1877}
1878
reed41af9662015-01-05 07:49:08 -08001879void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1880 this->onDrawOval(r, paint);
1881}
1882
1883void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1884 this->onDrawRRect(rrect, paint);
1885}
1886
1887void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1888 this->onDrawPoints(mode, count, pts, paint);
1889}
1890
1891void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001892 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001893 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reedfaba3712016-11-03 14:45:31 -04001894 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, bmode,
reed41af9662015-01-05 07:49:08 -08001895 indices, indexCount, paint);
1896}
1897
1898void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1899 this->onDrawPath(path, paint);
1900}
1901
reeda85d4d02015-05-06 12:56:48 -07001902void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001903 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001904 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001905}
1906
reede47829b2015-08-06 10:02:53 -07001907void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1908 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001909 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001910 if (dst.isEmpty() || src.isEmpty()) {
1911 return;
1912 }
1913 this->onDrawImageRect(image, &src, dst, paint, constraint);
1914}
reed41af9662015-01-05 07:49:08 -08001915
reed84984ef2015-07-17 07:09:43 -07001916void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1917 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001918 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001919 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001920}
1921
reede47829b2015-08-06 10:02:53 -07001922void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1923 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001924 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001925 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1926 constraint);
1927}
reede47829b2015-08-06 10:02:53 -07001928
reed4c21dc52015-06-25 12:32:03 -07001929void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1930 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001931 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001932 if (dst.isEmpty()) {
1933 return;
1934 }
msarett552bca92016-08-03 06:53:26 -07001935 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1936 this->onDrawImageNine(image, center, dst, paint);
1937 } else {
reede47829b2015-08-06 10:02:53 -07001938 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001939 }
reed4c21dc52015-06-25 12:32:03 -07001940}
1941
msarett16882062016-08-16 09:31:08 -07001942void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1943 const SkPaint* paint) {
1944 RETURN_ON_NULL(image);
1945 if (dst.isEmpty()) {
1946 return;
1947 }
msarett71df2d72016-09-30 12:41:42 -07001948
1949 SkIRect bounds;
1950 Lattice latticePlusBounds = lattice;
1951 if (!latticePlusBounds.fBounds) {
1952 bounds = SkIRect::MakeWH(image->width(), image->height());
1953 latticePlusBounds.fBounds = &bounds;
1954 }
1955
1956 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1957 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001958 } else {
1959 this->drawImageRect(image, dst, paint);
1960 }
1961}
1962
reed41af9662015-01-05 07:49:08 -08001963void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001964 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001965 return;
1966 }
reed41af9662015-01-05 07:49:08 -08001967 this->onDrawBitmap(bitmap, dx, dy, paint);
1968}
1969
reede47829b2015-08-06 10:02:53 -07001970void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001971 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001972 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001973 return;
1974 }
reede47829b2015-08-06 10:02:53 -07001975 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001976}
1977
reed84984ef2015-07-17 07:09:43 -07001978void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1979 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001980 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001981}
1982
reede47829b2015-08-06 10:02:53 -07001983void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1984 SrcRectConstraint constraint) {
1985 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1986 constraint);
1987}
reede47829b2015-08-06 10:02:53 -07001988
reed41af9662015-01-05 07:49:08 -08001989void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1990 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001991 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001992 return;
1993 }
msarett552bca92016-08-03 06:53:26 -07001994 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1995 this->onDrawBitmapNine(bitmap, center, dst, paint);
1996 } else {
reeda5517e22015-07-14 10:54:12 -07001997 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001998 }
reed41af9662015-01-05 07:49:08 -08001999}
2000
msarettc573a402016-08-02 08:05:56 -07002001void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2002 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002003 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002004 return;
2005 }
msarett71df2d72016-09-30 12:41:42 -07002006
2007 SkIRect bounds;
2008 Lattice latticePlusBounds = lattice;
2009 if (!latticePlusBounds.fBounds) {
2010 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2011 latticePlusBounds.fBounds = &bounds;
2012 }
2013
2014 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2015 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002016 } else {
msarett16882062016-08-16 09:31:08 -07002017 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002018 }
msarettc573a402016-08-02 08:05:56 -07002019}
2020
reed71c3c762015-06-24 10:29:17 -07002021void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002022 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002023 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002024 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002025 if (count <= 0) {
2026 return;
2027 }
2028 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002029 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002030 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002031}
2032
reedf70b5312016-03-04 16:36:20 -08002033void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2034 if (key) {
2035 this->onDrawAnnotation(rect, key, value);
2036 }
2037}
2038
reede47829b2015-08-06 10:02:53 -07002039void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2040 const SkPaint* paint, SrcRectConstraint constraint) {
2041 if (src) {
2042 this->drawImageRect(image, *src, dst, paint, constraint);
2043 } else {
2044 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2045 dst, paint, constraint);
2046 }
2047}
2048void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2049 const SkPaint* paint, SrcRectConstraint constraint) {
2050 if (src) {
2051 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2052 } else {
2053 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2054 dst, paint, constraint);
2055 }
2056}
2057
tomhudsoncb3bd182016-05-18 07:24:16 -07002058void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2059 SkIRect layer_bounds = this->getTopLayerBounds();
2060 if (matrix) {
2061 *matrix = this->getTotalMatrix();
2062 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2063 }
2064 if (clip_bounds) {
2065 this->getClipDeviceBounds(clip_bounds);
2066 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2067 }
2068}
2069
reed@android.com8a1c16f2008-12-17 15:59:43 +00002070//////////////////////////////////////////////////////////////////////////////
2071// These are the virtual drawing methods
2072//////////////////////////////////////////////////////////////////////////////
2073
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002074void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002075 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002076 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2077 }
2078}
2079
reed41af9662015-01-05 07:49:08 -08002080void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002081 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002082 this->internalDrawPaint(paint);
2083}
2084
2085void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002086 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002087
2088 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002089 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002090 }
2091
reed@google.com4e2b3d32011-04-07 14:18:59 +00002092 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093}
2094
reed41af9662015-01-05 07:49:08 -08002095void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2096 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002097 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002098 if ((long)count <= 0) {
2099 return;
2100 }
2101
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002102 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002103 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002104 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002105 // special-case 2 points (common for drawing a single line)
2106 if (2 == count) {
2107 r.set(pts[0], pts[1]);
2108 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002109 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002110 }
senorblanco87e066e2015-10-28 11:23:36 -07002111 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2112 return;
2113 }
2114 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002115 }
reed@google.coma584aed2012-05-16 14:06:02 +00002116
halcanary96fcdcc2015-08-27 07:41:13 -07002117 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002118
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002119 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002120
reed@android.com8a1c16f2008-12-17 15:59:43 +00002121 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002122 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002123 }
reed@google.com4b226022011-01-11 18:32:13 +00002124
reed@google.com4e2b3d32011-04-07 14:18:59 +00002125 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002126}
2127
reed4a167172016-08-18 17:15:25 -07002128static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2129 return ((intptr_t)paint.getImageFilter() |
2130#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2131 (intptr_t)canvas->getDrawFilter() |
2132#endif
2133 (intptr_t)paint.getLooper() ) != 0;
2134}
2135
reed41af9662015-01-05 07:49:08 -08002136void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002137 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002138 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002139 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002140 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002141 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2142 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2143 SkRect tmp(r);
2144 tmp.sort();
2145
senorblanco87e066e2015-10-28 11:23:36 -07002146 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2147 return;
2148 }
2149 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002150 }
reed@google.com4b226022011-01-11 18:32:13 +00002151
reed4a167172016-08-18 17:15:25 -07002152 if (needs_autodrawlooper(this, paint)) {
2153 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002154
reed4a167172016-08-18 17:15:25 -07002155 while (iter.next()) {
2156 iter.fDevice->drawRect(iter, r, looper.paint());
2157 }
2158
2159 LOOPER_END
2160 } else {
2161 this->predrawNotify(bounds, &paint, false);
2162 SkDrawIter iter(this);
2163 while (iter.next()) {
2164 iter.fDevice->drawRect(iter, r, paint);
2165 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002166 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002167}
2168
msarett44df6512016-08-25 13:54:30 -07002169void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2170 SkRect storage;
2171 SkRect regionRect = SkRect::Make(region.getBounds());
2172 const SkRect* bounds = nullptr;
2173 if (paint.canComputeFastBounds()) {
2174 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2175 return;
2176 }
2177 bounds = &regionRect;
2178 }
2179
2180 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2181
2182 while (iter.next()) {
2183 iter.fDevice->drawRegion(iter, region, looper.paint());
2184 }
2185
2186 LOOPER_END
2187}
2188
reed41af9662015-01-05 07:49:08 -08002189void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002190 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002191 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002192 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002193 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002194 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2195 return;
2196 }
2197 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002198 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002199
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002200 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002201
2202 while (iter.next()) {
2203 iter.fDevice->drawOval(iter, oval, looper.paint());
2204 }
2205
2206 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002207}
2208
bsalomonac3aa242016-08-19 11:25:19 -07002209void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2210 SkScalar sweepAngle, bool useCenter,
2211 const SkPaint& paint) {
2212 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2213 const SkRect* bounds = nullptr;
2214 if (paint.canComputeFastBounds()) {
2215 SkRect storage;
2216 // Note we're using the entire oval as the bounds.
2217 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2218 return;
2219 }
2220 bounds = &oval;
2221 }
2222
2223 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2224
2225 while (iter.next()) {
2226 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2227 }
2228
2229 LOOPER_END
2230}
2231
reed41af9662015-01-05 07:49:08 -08002232void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002233 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002234 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002235 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002236 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002237 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2238 return;
2239 }
2240 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002241 }
2242
2243 if (rrect.isRect()) {
2244 // call the non-virtual version
2245 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002246 return;
2247 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002248 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002249 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2250 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002251 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002252
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002253 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002254
2255 while (iter.next()) {
2256 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2257 }
2258
2259 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002260}
2261
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002262void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2263 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002264 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002265 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002266 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002267 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2268 return;
2269 }
2270 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002271 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002272
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002273 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002274
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002275 while (iter.next()) {
2276 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2277 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002278
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002279 LOOPER_END
2280}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002281
reed41af9662015-01-05 07:49:08 -08002282void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002283 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002284 if (!path.isFinite()) {
2285 return;
2286 }
2287
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002288 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002289 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002290 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002291 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002292 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2293 return;
2294 }
2295 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002296 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002297
2298 const SkRect& r = path.getBounds();
2299 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002300 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002301 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002302 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002303 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002304 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002306 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307
2308 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002309 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002310 }
2311
reed@google.com4e2b3d32011-04-07 14:18:59 +00002312 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002313}
2314
reed262a71b2015-12-05 13:07:27 -08002315bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002316 if (!paint.getImageFilter()) {
2317 return false;
2318 }
2319
2320 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002321 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002322 return false;
2323 }
2324
2325 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2326 // Once we can filter and the filter will return a result larger than itself, we should be
2327 // able to remove this constraint.
2328 // skbug.com/4526
2329 //
2330 SkPoint pt;
2331 ctm.mapXY(x, y, &pt);
2332 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2333 return ir.contains(fMCRec->fRasterClip.getBounds());
2334}
2335
reeda85d4d02015-05-06 12:56:48 -07002336void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002337 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002338 SkRect bounds = SkRect::MakeXYWH(x, y,
2339 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002340 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002341 SkRect tmp = bounds;
2342 if (paint) {
2343 paint->computeFastBounds(tmp, &tmp);
2344 }
2345 if (this->quickReject(tmp)) {
2346 return;
2347 }
reeda85d4d02015-05-06 12:56:48 -07002348 }
halcanary9d524f22016-03-29 09:03:52 -07002349
reeda85d4d02015-05-06 12:56:48 -07002350 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002351 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002352 paint = lazy.init();
2353 }
reed262a71b2015-12-05 13:07:27 -08002354
reeda2217ef2016-07-20 06:04:34 -07002355 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002356 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2357 *paint);
2358 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002359 special = this->getDevice()->makeSpecial(image);
2360 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002361 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002362 }
2363 }
2364
reed262a71b2015-12-05 13:07:27 -08002365 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2366
reeda85d4d02015-05-06 12:56:48 -07002367 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002368 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002369 if (special) {
2370 SkPoint pt;
2371 iter.fMatrix->mapXY(x, y, &pt);
2372 iter.fDevice->drawSpecial(iter, special.get(),
2373 SkScalarRoundToInt(pt.fX),
2374 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002375 } else {
2376 iter.fDevice->drawImage(iter, image, x, y, pnt);
2377 }
reeda85d4d02015-05-06 12:56:48 -07002378 }
halcanary9d524f22016-03-29 09:03:52 -07002379
reeda85d4d02015-05-06 12:56:48 -07002380 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002381}
2382
reed41af9662015-01-05 07:49:08 -08002383void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002384 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002385 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002386 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002387 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002388 if (paint) {
2389 paint->computeFastBounds(dst, &storage);
2390 }
2391 if (this->quickReject(storage)) {
2392 return;
2393 }
reeda85d4d02015-05-06 12:56:48 -07002394 }
2395 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002396 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002397 paint = lazy.init();
2398 }
halcanary9d524f22016-03-29 09:03:52 -07002399
senorblancoc41e7e12015-12-07 12:51:30 -08002400 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002401 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002402
reeda85d4d02015-05-06 12:56:48 -07002403 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002404 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002405 }
halcanary9d524f22016-03-29 09:03:52 -07002406
reeda85d4d02015-05-06 12:56:48 -07002407 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002408}
2409
reed41af9662015-01-05 07:49:08 -08002410void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002411 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002412 SkDEBUGCODE(bitmap.validate();)
2413
reed33366972015-10-08 09:22:02 -07002414 if (bitmap.drawsNothing()) {
2415 return;
2416 }
2417
2418 SkLazyPaint lazy;
2419 if (nullptr == paint) {
2420 paint = lazy.init();
2421 }
2422
2423 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2424
2425 SkRect storage;
2426 const SkRect* bounds = nullptr;
2427 if (paint->canComputeFastBounds()) {
2428 bitmap.getBounds(&storage);
2429 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002430 SkRect tmp = storage;
2431 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2432 return;
2433 }
2434 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002435 }
reed@google.com4b226022011-01-11 18:32:13 +00002436
reeda2217ef2016-07-20 06:04:34 -07002437 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002438 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2439 *paint);
2440 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002441 special = this->getDevice()->makeSpecial(bitmap);
2442 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002443 drawAsSprite = false;
2444 }
2445 }
2446
reed262a71b2015-12-05 13:07:27 -08002447 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002448
2449 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002450 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002451 if (special) {
reed262a71b2015-12-05 13:07:27 -08002452 SkPoint pt;
2453 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002454 iter.fDevice->drawSpecial(iter, special.get(),
2455 SkScalarRoundToInt(pt.fX),
2456 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002457 } else {
2458 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2459 }
reed33366972015-10-08 09:22:02 -07002460 }
msarettfbfa2582016-08-12 08:29:08 -07002461
reed33366972015-10-08 09:22:02 -07002462 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002463}
2464
reed@google.com9987ec32011-09-07 11:57:52 +00002465// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002466void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002467 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002468 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002469 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002470 return;
2471 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002472
halcanary96fcdcc2015-08-27 07:41:13 -07002473 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002474 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002475 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2476 return;
2477 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478 }
reed@google.com3d608122011-11-21 15:16:16 +00002479
reed@google.com33535f32012-09-25 15:37:50 +00002480 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002481 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002482 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002483 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002484
senorblancoc41e7e12015-12-07 12:51:30 -08002485 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002486 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002487
reed@google.com33535f32012-09-25 15:37:50 +00002488 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002489 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002490 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002491
reed@google.com33535f32012-09-25 15:37:50 +00002492 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002493}
2494
reed41af9662015-01-05 07:49:08 -08002495void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002496 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002497 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002498 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002499 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002500}
2501
reed4c21dc52015-06-25 12:32:03 -07002502void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2503 const SkPaint* paint) {
2504 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002505
halcanary96fcdcc2015-08-27 07:41:13 -07002506 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002507 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002508 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2509 return;
2510 }
reed@google.com3d608122011-11-21 15:16:16 +00002511 }
halcanary9d524f22016-03-29 09:03:52 -07002512
reed4c21dc52015-06-25 12:32:03 -07002513 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002514 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002515 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002516 }
halcanary9d524f22016-03-29 09:03:52 -07002517
senorblancoc41e7e12015-12-07 12:51:30 -08002518 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002519
reed4c21dc52015-06-25 12:32:03 -07002520 while (iter.next()) {
2521 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002522 }
halcanary9d524f22016-03-29 09:03:52 -07002523
reed4c21dc52015-06-25 12:32:03 -07002524 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002525}
2526
reed41af9662015-01-05 07:49:08 -08002527void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2528 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002529 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002530 SkDEBUGCODE(bitmap.validate();)
2531
halcanary96fcdcc2015-08-27 07:41:13 -07002532 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002533 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002534 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2535 return;
2536 }
reed4c21dc52015-06-25 12:32:03 -07002537 }
halcanary9d524f22016-03-29 09:03:52 -07002538
reed4c21dc52015-06-25 12:32:03 -07002539 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002540 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002541 paint = lazy.init();
2542 }
halcanary9d524f22016-03-29 09:03:52 -07002543
senorblancoc41e7e12015-12-07 12:51:30 -08002544 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002545
reed4c21dc52015-06-25 12:32:03 -07002546 while (iter.next()) {
2547 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2548 }
halcanary9d524f22016-03-29 09:03:52 -07002549
reed4c21dc52015-06-25 12:32:03 -07002550 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002551}
2552
msarett16882062016-08-16 09:31:08 -07002553void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2554 const SkPaint* paint) {
2555 if (nullptr == paint || paint->canComputeFastBounds()) {
2556 SkRect storage;
2557 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2558 return;
2559 }
2560 }
2561
2562 SkLazyPaint lazy;
2563 if (nullptr == paint) {
2564 paint = lazy.init();
2565 }
2566
2567 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2568
2569 while (iter.next()) {
2570 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2571 }
2572
2573 LOOPER_END
2574}
2575
2576void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2577 const SkRect& dst, const SkPaint* paint) {
2578 if (nullptr == paint || paint->canComputeFastBounds()) {
2579 SkRect storage;
2580 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2581 return;
2582 }
2583 }
2584
2585 SkLazyPaint lazy;
2586 if (nullptr == paint) {
2587 paint = lazy.init();
2588 }
2589
2590 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2591
2592 while (iter.next()) {
2593 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2594 }
2595
2596 LOOPER_END
2597}
2598
reed@google.comf67e4cf2011-03-15 20:56:58 +00002599class SkDeviceFilteredPaint {
2600public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002601 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002602 uint32_t filteredFlags = device->filterTextFlags(paint);
2603 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002604 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002605 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002606 fPaint = newPaint;
2607 } else {
2608 fPaint = &paint;
2609 }
2610 }
2611
reed@google.comf67e4cf2011-03-15 20:56:58 +00002612 const SkPaint& paint() const { return *fPaint; }
2613
2614private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002615 const SkPaint* fPaint;
2616 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002617};
2618
bungeman@google.com52c748b2011-08-22 21:30:43 +00002619void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2620 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002621 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002622 draw.fDevice->drawRect(draw, r, paint);
2623 } else {
2624 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002625 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002626 draw.fDevice->drawRect(draw, r, p);
2627 }
2628}
2629
2630void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2631 const char text[], size_t byteLength,
2632 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002633 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002634
2635 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002636 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002637 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002638 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002639 return;
2640 }
2641
2642 SkScalar width = 0;
2643 SkPoint start;
2644
2645 start.set(0, 0); // to avoid warning
2646 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2647 SkPaint::kStrikeThruText_Flag)) {
2648 width = paint.measureText(text, byteLength);
2649
2650 SkScalar offsetX = 0;
2651 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2652 offsetX = SkScalarHalf(width);
2653 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2654 offsetX = width;
2655 }
2656 start.set(x - offsetX, y);
2657 }
2658
2659 if (0 == width) {
2660 return;
2661 }
2662
2663 uint32_t flags = paint.getFlags();
2664
2665 if (flags & (SkPaint::kUnderlineText_Flag |
2666 SkPaint::kStrikeThruText_Flag)) {
2667 SkScalar textSize = paint.getTextSize();
2668 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2669 SkRect r;
2670
2671 r.fLeft = start.fX;
2672 r.fRight = start.fX + width;
2673
2674 if (flags & SkPaint::kUnderlineText_Flag) {
2675 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2676 start.fY);
2677 r.fTop = offset;
2678 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002679 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002680 }
2681 if (flags & SkPaint::kStrikeThruText_Flag) {
2682 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2683 start.fY);
2684 r.fTop = offset;
2685 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002686 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002687 }
2688 }
2689}
2690
reed@google.come0d9ce82014-04-23 04:00:17 +00002691void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2692 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002693 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002694
2695 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002696 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002697 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002698 DrawTextDecorations(iter, dfp.paint(),
2699 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002700 }
2701
reed@google.com4e2b3d32011-04-07 14:18:59 +00002702 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002703}
2704
reed@google.come0d9ce82014-04-23 04:00:17 +00002705void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2706 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002707 SkPoint textOffset = SkPoint::Make(0, 0);
2708
halcanary96fcdcc2015-08-27 07:41:13 -07002709 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002710
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002712 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002713 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002714 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002715 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002716
reed@google.com4e2b3d32011-04-07 14:18:59 +00002717 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002718}
2719
reed@google.come0d9ce82014-04-23 04:00:17 +00002720void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2721 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002722
2723 SkPoint textOffset = SkPoint::Make(0, constY);
2724
halcanary96fcdcc2015-08-27 07:41:13 -07002725 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002726
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002728 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002729 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002730 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002731 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002732
reed@google.com4e2b3d32011-04-07 14:18:59 +00002733 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002734}
2735
reed@google.come0d9ce82014-04-23 04:00:17 +00002736void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2737 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002738 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002739
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740 while (iter.next()) {
2741 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002742 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002743 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002744
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002745 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002746}
2747
reed45561a02016-07-07 12:47:17 -07002748void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2749 const SkRect* cullRect, const SkPaint& paint) {
2750 if (cullRect && this->quickReject(*cullRect)) {
2751 return;
2752 }
2753
2754 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2755
2756 while (iter.next()) {
2757 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2758 }
2759
2760 LOOPER_END
2761}
2762
fmalita00d5c2c2014-08-21 08:53:26 -07002763void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2764 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002765
fmalita85d5eb92015-03-04 11:20:12 -08002766 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002767 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002768 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002769 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002770 SkRect tmp;
2771 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2772 return;
2773 }
2774 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002775 }
2776
fmalita024f9962015-03-03 19:08:17 -08002777 // We cannot filter in the looper as we normally do, because the paint is
2778 // incomplete at this point (text-related attributes are embedded within blob run paints).
2779 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002780 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002781
fmalita85d5eb92015-03-04 11:20:12 -08002782 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002783
fmalitaaa1b9122014-08-28 14:32:24 -07002784 while (iter.next()) {
2785 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002786 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002787 }
2788
fmalitaaa1b9122014-08-28 14:32:24 -07002789 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002790
2791 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002792}
2793
reed@google.come0d9ce82014-04-23 04:00:17 +00002794// These will become non-virtual, so they always call the (virtual) onDraw... method
2795void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2796 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002797 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002798 if (byteLength) {
2799 this->onDrawText(text, byteLength, x, y, paint);
2800 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002801}
2802void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2803 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002804 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002805 if (byteLength) {
2806 this->onDrawPosText(text, byteLength, pos, paint);
2807 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002808}
2809void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2810 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002811 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002812 if (byteLength) {
2813 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2814 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002815}
2816void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2817 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002818 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002819 if (byteLength) {
2820 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2821 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002822}
reed45561a02016-07-07 12:47:17 -07002823void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2824 const SkRect* cullRect, const SkPaint& paint) {
2825 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2826 if (byteLength) {
2827 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2828 }
2829}
fmalita00d5c2c2014-08-21 08:53:26 -07002830void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2831 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002832 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002833 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002834 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002835}
reed@google.come0d9ce82014-04-23 04:00:17 +00002836
reed41af9662015-01-05 07:49:08 -08002837void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2838 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002839 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002840 const uint16_t indices[], int indexCount,
2841 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002842 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002843 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002844
reed@android.com8a1c16f2008-12-17 15:59:43 +00002845 while (iter.next()) {
2846 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002847 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002848 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849 }
reed@google.com4b226022011-01-11 18:32:13 +00002850
reed@google.com4e2b3d32011-04-07 14:18:59 +00002851 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002852}
2853
dandovb3c9d1c2014-08-12 08:34:29 -07002854void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002855 const SkPoint texCoords[4], SkBlendMode bmode,
2856 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002857 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002858 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002859 return;
2860 }
mtklein6cfa73a2014-08-13 13:33:49 -07002861
Mike Reedfaba3712016-11-03 14:45:31 -04002862 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002863}
2864
2865void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002866 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002867 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002868 // Since a patch is always within the convex hull of the control points, we discard it when its
2869 // bounding rectangle is completely outside the current clip.
2870 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002871 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002872 if (this->quickReject(bounds)) {
2873 return;
2874 }
mtklein6cfa73a2014-08-13 13:33:49 -07002875
halcanary96fcdcc2015-08-27 07:41:13 -07002876 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002877
dandovecfff212014-08-04 10:02:00 -07002878 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002879 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002880 }
mtklein6cfa73a2014-08-13 13:33:49 -07002881
dandovecfff212014-08-04 10:02:00 -07002882 LOOPER_END
2883}
2884
reeda8db7282015-07-07 10:22:31 -07002885void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002886 RETURN_ON_NULL(dr);
2887 if (x || y) {
2888 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2889 this->onDrawDrawable(dr, &matrix);
2890 } else {
2891 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002892 }
2893}
2894
reeda8db7282015-07-07 10:22:31 -07002895void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002896 RETURN_ON_NULL(dr);
2897 if (matrix && matrix->isIdentity()) {
2898 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002899 }
reede3b38ce2016-01-08 09:18:44 -08002900 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002901}
2902
2903void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002904 // drawable bounds are no longer reliable (e.g. android displaylist)
2905 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002906 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002907}
2908
reed71c3c762015-06-24 10:29:17 -07002909void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002910 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002911 const SkRect* cull, const SkPaint* paint) {
2912 if (cull && this->quickReject(*cull)) {
2913 return;
2914 }
2915
2916 SkPaint pnt;
2917 if (paint) {
2918 pnt = *paint;
2919 }
halcanary9d524f22016-03-29 09:03:52 -07002920
halcanary96fcdcc2015-08-27 07:41:13 -07002921 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002922 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002923 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002924 }
2925 LOOPER_END
2926}
2927
reedf70b5312016-03-04 16:36:20 -08002928void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2929 SkASSERT(key);
2930
2931 SkPaint paint;
2932 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2933 while (iter.next()) {
2934 iter.fDevice->drawAnnotation(iter, rect, key, value);
2935 }
2936 LOOPER_END
2937}
2938
reed@android.com8a1c16f2008-12-17 15:59:43 +00002939//////////////////////////////////////////////////////////////////////////////
2940// These methods are NOT virtual, and therefore must call back into virtual
2941// methods, rather than actually drawing themselves.
2942//////////////////////////////////////////////////////////////////////////////
2943
reed374772b2016-10-05 17:33:02 -07002944void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002945 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002946 SkPaint paint;
2947
2948 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002949 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002950 this->drawPaint(paint);
2951}
2952
reed374772b2016-10-05 17:33:02 -07002953void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002954 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002955 SkPaint paint;
2956
2957 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002958 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002959 this->drawPaint(paint);
2960}
2961
2962void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002963 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002964 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002965
reed@android.com8a1c16f2008-12-17 15:59:43 +00002966 pt.set(x, y);
2967 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2968}
2969
2970void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002971 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002972 SkPoint pt;
2973 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002974
reed@android.com8a1c16f2008-12-17 15:59:43 +00002975 pt.set(x, y);
2976 paint.setColor(color);
2977 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2978}
2979
2980void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2981 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002982 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002983 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002984
reed@android.com8a1c16f2008-12-17 15:59:43 +00002985 pts[0].set(x0, y0);
2986 pts[1].set(x1, y1);
2987 this->drawPoints(kLines_PointMode, 2, pts, paint);
2988}
2989
2990void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2991 SkScalar right, SkScalar bottom,
2992 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002993 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002994 SkRect r;
2995
2996 r.set(left, top, right, bottom);
2997 this->drawRect(r, paint);
2998}
2999
3000void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3001 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003002 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003003 if (radius < 0) {
3004 radius = 0;
3005 }
3006
3007 SkRect r;
3008 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003009 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003010}
3011
3012void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3013 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003014 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003015 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003016 SkRRect rrect;
3017 rrect.setRectXY(r, rx, ry);
3018 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003019 } else {
3020 this->drawRect(r, paint);
3021 }
3022}
3023
reed@android.com8a1c16f2008-12-17 15:59:43 +00003024void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3025 SkScalar sweepAngle, bool useCenter,
3026 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003027 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003028 if (oval.isEmpty() || !sweepAngle) {
3029 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003030 }
bsalomon21af9ca2016-08-25 12:29:23 -07003031 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003032}
3033
3034void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3035 const SkPath& path, SkScalar hOffset,
3036 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003037 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003038 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003039
reed@android.com8a1c16f2008-12-17 15:59:43 +00003040 matrix.setTranslate(hOffset, vOffset);
3041 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3042}
3043
reed@android.comf76bacf2009-05-13 14:00:33 +00003044///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003045
3046/**
3047 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3048 * against the playback cost of recursing into the subpicture to get at its actual ops.
3049 *
3050 * For now we pick a conservatively small value, though measurement (and other heuristics like
3051 * the type of ops contained) may justify changing this value.
3052 */
3053#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003054
reedd5fa1a42014-08-09 11:08:05 -07003055void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003056 RETURN_ON_NULL(picture);
3057
reed1c2c4412015-04-30 13:09:24 -07003058 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003059 if (matrix && matrix->isIdentity()) {
3060 matrix = nullptr;
3061 }
3062 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3063 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3064 picture->playback(this);
3065 } else {
3066 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003067 }
3068}
robertphillips9b14f262014-06-04 05:40:44 -07003069
reedd5fa1a42014-08-09 11:08:05 -07003070void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3071 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003072 if (!paint || paint->canComputeFastBounds()) {
3073 SkRect bounds = picture->cullRect();
3074 if (paint) {
3075 paint->computeFastBounds(bounds, &bounds);
3076 }
3077 if (matrix) {
3078 matrix->mapRect(&bounds);
3079 }
3080 if (this->quickReject(bounds)) {
3081 return;
3082 }
3083 }
3084
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003085 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003086 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003087}
3088
vjiaoblack95302da2016-07-21 10:25:54 -07003089#ifdef SK_EXPERIMENTAL_SHADOWING
3090void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3091 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003092 const SkPaint* paint,
3093 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003094 RETURN_ON_NULL(picture);
3095
3096 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3097
vjiaoblacke6f5d562016-08-25 06:30:23 -07003098 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003099}
3100
3101void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3102 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003103 const SkPaint* paint,
3104 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003105 if (!paint || paint->canComputeFastBounds()) {
3106 SkRect bounds = picture->cullRect();
3107 if (paint) {
3108 paint->computeFastBounds(bounds, &bounds);
3109 }
3110 if (matrix) {
3111 matrix->mapRect(&bounds);
3112 }
3113 if (this->quickReject(bounds)) {
3114 return;
3115 }
3116 }
3117
3118 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3119
vjiaoblacke6f5d562016-08-25 06:30:23 -07003120 sk_sp<SkImage> povDepthMap;
3121 sk_sp<SkImage> diffuseMap;
3122
vjiaoblack904527d2016-08-09 09:32:09 -07003123 // povDepthMap
3124 {
3125 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003126 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3127 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003128 sk_sp<SkLights> povLight = builder.finish();
3129
3130 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3131 picture->cullRect().height(),
3132 kBGRA_8888_SkColorType,
3133 kOpaque_SkAlphaType);
3134
3135 // Create a new surface (that matches the backend of canvas)
3136 // to create the povDepthMap
3137 sk_sp<SkSurface> surf(this->makeSurface(info));
3138
3139 // Wrap another SPFCanvas around the surface
3140 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3141 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3142
3143 // set the depth map canvas to have the light as the user's POV
3144 depthMapCanvas->setLights(std::move(povLight));
3145
3146 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003147 povDepthMap = surf->makeImageSnapshot();
3148 }
3149
3150 // diffuseMap
3151 {
3152 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3153 picture->cullRect().height(),
3154 kBGRA_8888_SkColorType,
3155 kOpaque_SkAlphaType);
3156
3157 sk_sp<SkSurface> surf(this->makeSurface(info));
3158 surf->getCanvas()->drawPicture(picture);
3159
3160 diffuseMap = surf->makeImageSnapshot();
3161 }
vjiaoblack904527d2016-08-09 09:32:09 -07003162
3163 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3164 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003165 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3166 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003167
3168 // TODO: pass the depth to the shader in vertices, or uniforms
3169 // so we don't have to render depth and color separately
3170 for (int i = 0; i < fLights->numLights(); ++i) {
3171 // skip over ambient lights; they don't cast shadows
3172 // lights that have shadow maps do not need updating (because lights are immutable)
3173 sk_sp<SkImage> depthMap;
3174 SkISize shMapSize;
3175
3176 if (fLights->light(i).getShadowMap() != nullptr) {
3177 continue;
3178 }
3179
3180 if (fLights->light(i).isRadial()) {
3181 shMapSize.fHeight = 1;
3182 shMapSize.fWidth = (int) picture->cullRect().width();
3183
3184 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3185 kBGRA_8888_SkColorType,
3186 kOpaque_SkAlphaType);
3187
3188 // Create new surface (that matches the backend of canvas)
3189 // for each shadow map
3190 sk_sp<SkSurface> surf(this->makeSurface(info));
3191
3192 // Wrap another SPFCanvas around the surface
3193 SkCanvas* depthMapCanvas = surf->getCanvas();
3194
3195 SkLights::Builder builder;
3196 builder.add(fLights->light(i));
3197 sk_sp<SkLights> curLight = builder.finish();
3198
3199 sk_sp<SkShader> shadowMapShader;
3200 shadowMapShader = SkRadialShadowMapShader::Make(
3201 povDepthShader, curLight,
3202 (int) picture->cullRect().width(),
3203 (int) picture->cullRect().height());
3204
3205 SkPaint shadowMapPaint;
3206 shadowMapPaint.setShader(std::move(shadowMapShader));
3207
3208 depthMapCanvas->setLights(curLight);
3209
3210 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3211 diffuseMap->height()),
3212 shadowMapPaint);
3213
3214 depthMap = surf->makeImageSnapshot();
3215
3216 } else {
3217 // TODO: compute the correct size of the depth map from the light properties
3218 // TODO: maybe add a kDepth_8_SkColorType
3219 // TODO: find actual max depth of picture
3220 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3221 fLights->light(i), 255,
3222 (int) picture->cullRect().width(),
3223 (int) picture->cullRect().height());
3224
3225 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3226 kBGRA_8888_SkColorType,
3227 kOpaque_SkAlphaType);
3228
3229 // Create a new surface (that matches the backend of canvas)
3230 // for each shadow map
3231 sk_sp<SkSurface> surf(this->makeSurface(info));
3232
3233 // Wrap another SPFCanvas around the surface
3234 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3235 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3236 depthMapCanvas->setShadowParams(params);
3237
3238 // set the depth map canvas to have the light we're drawing.
3239 SkLights::Builder builder;
3240 builder.add(fLights->light(i));
3241 sk_sp<SkLights> curLight = builder.finish();
3242 depthMapCanvas->setLights(std::move(curLight));
3243
3244 depthMapCanvas->drawPicture(picture);
3245 depthMap = surf->makeImageSnapshot();
3246 }
3247
3248 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3249 fLights->light(i).setShadowMap(std::move(depthMap));
3250 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3251 // we blur the variance map
3252 SkPaint blurPaint;
3253 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3254 params.fShadowRadius, nullptr));
3255
3256 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3257 kBGRA_8888_SkColorType,
3258 kOpaque_SkAlphaType);
3259
3260 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3261
3262 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3263
3264 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3265 }
3266 }
3267
3268 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003269 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3270 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003271 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003272 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003273 diffuseMap->height(),
3274 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003275
3276 shadowPaint.setShader(shadowShader);
3277
3278 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003279}
3280#endif
3281
reed@android.com8a1c16f2008-12-17 15:59:43 +00003282///////////////////////////////////////////////////////////////////////////////
3283///////////////////////////////////////////////////////////////////////////////
3284
reed3aafe112016-08-18 12:45:34 -07003285SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003286 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003287
3288 SkASSERT(canvas);
3289
reed3aafe112016-08-18 12:45:34 -07003290 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003291 fDone = !fImpl->next();
3292}
3293
3294SkCanvas::LayerIter::~LayerIter() {
3295 fImpl->~SkDrawIter();
3296}
3297
3298void SkCanvas::LayerIter::next() {
3299 fDone = !fImpl->next();
3300}
3301
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003302SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003303 return fImpl->getDevice();
3304}
3305
3306const SkMatrix& SkCanvas::LayerIter::matrix() const {
3307 return fImpl->getMatrix();
3308}
3309
3310const SkPaint& SkCanvas::LayerIter::paint() const {
3311 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003312 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003313 paint = &fDefaultPaint;
3314 }
3315 return *paint;
3316}
3317
reed1e7f5e72016-04-27 07:49:17 -07003318const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003319int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3320int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003321
3322///////////////////////////////////////////////////////////////////////////////
3323
fmalitac3b589a2014-06-05 12:40:07 -07003324SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003325
3326///////////////////////////////////////////////////////////////////////////////
3327
3328static bool supported_for_raster_canvas(const SkImageInfo& info) {
3329 switch (info.alphaType()) {
3330 case kPremul_SkAlphaType:
3331 case kOpaque_SkAlphaType:
3332 break;
3333 default:
3334 return false;
3335 }
3336
3337 switch (info.colorType()) {
3338 case kAlpha_8_SkColorType:
3339 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003340 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003341 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003342 break;
3343 default:
3344 return false;
3345 }
3346
3347 return true;
3348}
3349
Mike Reed5df49342016-11-12 08:06:55 -06003350std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3351 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003352 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003353 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003354 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003355
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003356 SkBitmap bitmap;
3357 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003358 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003359 }
Mike Reed5df49342016-11-12 08:06:55 -06003360 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003361}
reedd5fa1a42014-08-09 11:08:05 -07003362
3363///////////////////////////////////////////////////////////////////////////////
3364
3365SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003366 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003367 : fCanvas(canvas)
3368 , fSaveCount(canvas->getSaveCount())
3369{
bsalomon49f085d2014-09-05 13:34:00 -07003370 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003371 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003372 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003373 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003374 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003375 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003376 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003377 canvas->save();
3378 }
mtklein6cfa73a2014-08-13 13:33:49 -07003379
bsalomon49f085d2014-09-05 13:34:00 -07003380 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003381 canvas->concat(*matrix);
3382 }
3383}
3384
3385SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3386 fCanvas->restoreToCount(fSaveCount);
3387}
reede8f30622016-03-23 18:59:25 -07003388
Florin Malitaee424ac2016-12-01 12:47:59 -05003389///////////////////////////////////////////////////////////////////////////////
3390
3391SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3392 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3393
Florin Malita439ace92016-12-02 12:05:41 -05003394SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3395 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3396
Florin Malitaee424ac2016-12-01 12:47:59 -05003397SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3398 (void)this->INHERITED::getSaveLayerStrategy(rec);
3399 return kNoLayer_SaveLayerStrategy;
3400}
3401
3402///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003403
reed73603f32016-09-20 08:42:38 -07003404static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3405static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3406static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3407static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3408static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3409static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003410
3411///////////////////////////////////////////////////////////////////////////////////////////////////
3412
3413SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3414 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3415 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3416 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3417 SkIPoint origin = dev->getOrigin();
3418 SkMatrix ctm = this->getTotalMatrix();
3419 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3420
3421 SkIRect clip = fMCRec->fRasterClip.getBounds();
3422 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003423 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003424 clip.setEmpty();
3425 }
3426
3427 fAllocator->updateHandle(handle, ctm, clip);
3428 return handle;
3429 }
3430 return nullptr;
3431}
3432
3433static bool install(SkBitmap* bm, const SkImageInfo& info,
3434 const SkRasterHandleAllocator::Rec& rec) {
3435 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3436 rec.fReleaseProc, rec.fReleaseCtx);
3437}
3438
3439SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3440 SkBitmap* bm) {
3441 SkRasterHandleAllocator::Rec rec;
3442 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3443 return nullptr;
3444 }
3445 return rec.fHandle;
3446}
3447
3448std::unique_ptr<SkCanvas>
3449SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3450 const SkImageInfo& info, const Rec* rec) {
3451 if (!alloc || !supported_for_raster_canvas(info)) {
3452 return nullptr;
3453 }
3454
3455 SkBitmap bm;
3456 Handle hndl;
3457
3458 if (rec) {
3459 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3460 } else {
3461 hndl = alloc->allocBitmap(info, &bm);
3462 }
3463 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3464}