blob: d57b62fa99f70068aad2142e28c7ab638c5451d6 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Mike Reed986480a2017-01-13 22:43:16 +00008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080018#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070019#include "SkImageFilter.h"
20#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070021#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060022#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050025#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070026#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070027#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070028#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000029#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070030#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000031#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050032#include "SkRasterHandleAllocator.h"
Matt Sarett26ecfe02017-01-23 15:51:01 +000033#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) {
Matt Sarett26ecfe02017-01-23 15:51:01 +0000861 if (kUnknown_SkColorType == bitmap->colorType()) {
862 return false;
863 }
864
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000865 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 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000911 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800912
Matt Sarett26ecfe02017-01-23 15:51:01 +0000913 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
914 if (!rec.trim(size.width(), size.height())) {
915 return false;
916 }
917
918 // The device can assert that the requested area is always contained in its bounds
919 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
Matt Sarett26ecfe02017-01-23 15:51:01 +0000931bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000932 int x, int y) {
Matt Sarett26ecfe02017-01-23 15:51:01 +0000933 switch (origInfo.colorType()) {
934 case kUnknown_SkColorType:
935 case kIndex_8_SkColorType:
936 return false;
937 default:
938 break;
939 }
940 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
941 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
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000950 SkBaseDevice* device = this->getDevice();
951 if (!device) {
952 return false;
953 }
954
Matt Sarett26ecfe02017-01-23 15:51:01 +0000955 // the intersect may have shrunk info's logical size
956 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000957
Matt Sarett26ecfe02017-01-23 15:51:01 +0000958 // 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
968 // Tell our owning surface to bump its generation ID
969 const bool completeOverwrite = info.dimensions() == size;
reedc83a2972015-07-16 07:40:45 -0700970 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700971
Matt Sarett26ecfe02017-01-23 15:51:01 +0000972 // The device can assert that the requested area is always contained in its bounds
973 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) {
Mike Reed918e1442017-01-23 11:39:45 -05001077 SkIRect clipBounds = this->getDeviceClipBounds();
1078 if (clipBounds.isEmpty()) {
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 {
Mike Reed918e1442017-01-23 11:39:45 -05001777 SkIRect ibounds = this->getDeviceClipBounds();
1778 if (ibounds.isEmpty()) {
1779 if (bounds) {
1780 bounds->setEmpty();
1781 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001782 return false;
1783 }
1784
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001785 SkMatrix inverse;
1786 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001787 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001788 if (bounds) {
1789 bounds->setEmpty();
1790 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001791 return false;
1792 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001793
bsalomon49f085d2014-09-05 13:34:00 -07001794 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001795 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001796 // adjust it outwards in case we are antialiasing
1797 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001798
reed@google.com8f4d2302013-12-17 16:44:46 +00001799 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1800 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001801 inverse.mapRect(bounds, r);
1802 }
1803 return true;
1804}
1805
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001806bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001807 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001808 if (clip.isEmpty()) {
1809 if (bounds) {
1810 bounds->setEmpty();
1811 }
1812 return false;
1813 }
1814
bsalomon49f085d2014-09-05 13:34:00 -07001815 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001816 *bounds = clip.getBounds();
1817 }
1818 return true;
1819}
1820
reed@android.com8a1c16f2008-12-17 15:59:43 +00001821const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001822 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001823}
1824
Mike Reed3726a4a2017-01-19 11:36:41 -05001825void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1826 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1827 if (this->getGrContext()) {
1828 SkPath path;
1829 this->getClipStack()->asPath(&path);
1830 SkISize size = this->getBaseLayerSize();
1831 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1832 } else {
1833 *rgn = fMCRec->fRasterClip.forceGetBW();
1834 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001835}
1836
Brian Osman11052242016-10-27 14:47:55 -04001837GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001838 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001839 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001840}
1841
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001842GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001843 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001844 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001845}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001846
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001847void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1848 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001849 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001850 if (outer.isEmpty()) {
1851 return;
1852 }
1853 if (inner.isEmpty()) {
1854 this->drawRRect(outer, paint);
1855 return;
1856 }
1857
1858 // We don't have this method (yet), but technically this is what we should
1859 // be able to assert...
1860 // SkASSERT(outer.contains(inner));
1861 //
1862 // For now at least check for containment of bounds
1863 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1864
1865 this->onDrawDRRect(outer, inner, paint);
1866}
1867
reed41af9662015-01-05 07:49:08 -08001868// These need to stop being virtual -- clients need to override the onDraw... versions
1869
1870void SkCanvas::drawPaint(const SkPaint& paint) {
1871 this->onDrawPaint(paint);
1872}
1873
1874void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1875 this->onDrawRect(r, paint);
1876}
1877
msarettdca352e2016-08-26 06:37:45 -07001878void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1879 if (region.isEmpty()) {
1880 return;
1881 }
1882
1883 if (region.isRect()) {
1884 return this->drawIRect(region.getBounds(), paint);
1885 }
1886
1887 this->onDrawRegion(region, paint);
1888}
1889
reed41af9662015-01-05 07:49:08 -08001890void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1891 this->onDrawOval(r, paint);
1892}
1893
1894void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1895 this->onDrawRRect(rrect, paint);
1896}
1897
1898void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1899 this->onDrawPoints(mode, count, pts, paint);
1900}
1901
1902void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001903 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001904 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reedfaba3712016-11-03 14:45:31 -04001905 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, bmode,
reed41af9662015-01-05 07:49:08 -08001906 indices, indexCount, paint);
1907}
1908
1909void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1910 this->onDrawPath(path, paint);
1911}
1912
reeda85d4d02015-05-06 12:56:48 -07001913void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001914 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001915 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001916}
1917
reede47829b2015-08-06 10:02:53 -07001918void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1919 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001920 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001921 if (dst.isEmpty() || src.isEmpty()) {
1922 return;
1923 }
1924 this->onDrawImageRect(image, &src, dst, paint, constraint);
1925}
reed41af9662015-01-05 07:49:08 -08001926
reed84984ef2015-07-17 07:09:43 -07001927void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1928 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001929 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001930 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001931}
1932
reede47829b2015-08-06 10:02:53 -07001933void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1934 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001935 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001936 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1937 constraint);
1938}
reede47829b2015-08-06 10:02:53 -07001939
reed4c21dc52015-06-25 12:32:03 -07001940void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1941 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001942 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001943 if (dst.isEmpty()) {
1944 return;
1945 }
msarett552bca92016-08-03 06:53:26 -07001946 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1947 this->onDrawImageNine(image, center, dst, paint);
1948 } else {
reede47829b2015-08-06 10:02:53 -07001949 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001950 }
reed4c21dc52015-06-25 12:32:03 -07001951}
1952
msarett16882062016-08-16 09:31:08 -07001953void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1954 const SkPaint* paint) {
1955 RETURN_ON_NULL(image);
1956 if (dst.isEmpty()) {
1957 return;
1958 }
msarett71df2d72016-09-30 12:41:42 -07001959
1960 SkIRect bounds;
1961 Lattice latticePlusBounds = lattice;
1962 if (!latticePlusBounds.fBounds) {
1963 bounds = SkIRect::MakeWH(image->width(), image->height());
1964 latticePlusBounds.fBounds = &bounds;
1965 }
1966
1967 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1968 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001969 } else {
1970 this->drawImageRect(image, dst, paint);
1971 }
1972}
1973
reed41af9662015-01-05 07:49:08 -08001974void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001975 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001976 return;
1977 }
reed41af9662015-01-05 07:49:08 -08001978 this->onDrawBitmap(bitmap, dx, dy, paint);
1979}
1980
reede47829b2015-08-06 10:02:53 -07001981void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001982 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001983 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001984 return;
1985 }
reede47829b2015-08-06 10:02:53 -07001986 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001987}
1988
reed84984ef2015-07-17 07:09:43 -07001989void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1990 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001991 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001992}
1993
reede47829b2015-08-06 10:02:53 -07001994void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1995 SrcRectConstraint constraint) {
1996 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1997 constraint);
1998}
reede47829b2015-08-06 10:02:53 -07001999
reed41af9662015-01-05 07:49:08 -08002000void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2001 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002002 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002003 return;
2004 }
msarett552bca92016-08-03 06:53:26 -07002005 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2006 this->onDrawBitmapNine(bitmap, center, dst, paint);
2007 } else {
reeda5517e22015-07-14 10:54:12 -07002008 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002009 }
reed41af9662015-01-05 07:49:08 -08002010}
2011
msarettc573a402016-08-02 08:05:56 -07002012void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2013 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002014 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002015 return;
2016 }
msarett71df2d72016-09-30 12:41:42 -07002017
2018 SkIRect bounds;
2019 Lattice latticePlusBounds = lattice;
2020 if (!latticePlusBounds.fBounds) {
2021 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2022 latticePlusBounds.fBounds = &bounds;
2023 }
2024
2025 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2026 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002027 } else {
msarett16882062016-08-16 09:31:08 -07002028 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002029 }
msarettc573a402016-08-02 08:05:56 -07002030}
2031
reed71c3c762015-06-24 10:29:17 -07002032void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002033 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002034 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002035 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002036 if (count <= 0) {
2037 return;
2038 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002039 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002040 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002041 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002042}
2043
reedf70b5312016-03-04 16:36:20 -08002044void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2045 if (key) {
2046 this->onDrawAnnotation(rect, key, value);
2047 }
2048}
2049
reede47829b2015-08-06 10:02:53 -07002050void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2051 const SkPaint* paint, SrcRectConstraint constraint) {
2052 if (src) {
2053 this->drawImageRect(image, *src, dst, paint, constraint);
2054 } else {
2055 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2056 dst, paint, constraint);
2057 }
2058}
2059void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2060 const SkPaint* paint, SrcRectConstraint constraint) {
2061 if (src) {
2062 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2063 } else {
2064 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2065 dst, paint, constraint);
2066 }
2067}
2068
tomhudsoncb3bd182016-05-18 07:24:16 -07002069void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2070 SkIRect layer_bounds = this->getTopLayerBounds();
2071 if (matrix) {
2072 *matrix = this->getTotalMatrix();
2073 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2074 }
2075 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002076 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002077 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2078 }
2079}
2080
reed@android.com8a1c16f2008-12-17 15:59:43 +00002081//////////////////////////////////////////////////////////////////////////////
2082// These are the virtual drawing methods
2083//////////////////////////////////////////////////////////////////////////////
2084
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002085void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002086 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002087 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2088 }
2089}
2090
reed41af9662015-01-05 07:49:08 -08002091void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002092 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002093 this->internalDrawPaint(paint);
2094}
2095
2096void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002097 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002098
2099 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002100 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002101 }
2102
reed@google.com4e2b3d32011-04-07 14:18:59 +00002103 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002104}
2105
reed41af9662015-01-05 07:49:08 -08002106void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2107 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002108 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002109 if ((long)count <= 0) {
2110 return;
2111 }
2112
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002113 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002114 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002115 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002116 // special-case 2 points (common for drawing a single line)
2117 if (2 == count) {
2118 r.set(pts[0], pts[1]);
2119 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002120 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002121 }
senorblanco87e066e2015-10-28 11:23:36 -07002122 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2123 return;
2124 }
2125 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002126 }
reed@google.coma584aed2012-05-16 14:06:02 +00002127
halcanary96fcdcc2015-08-27 07:41:13 -07002128 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002129
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002130 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002131
reed@android.com8a1c16f2008-12-17 15:59:43 +00002132 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002133 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002134 }
reed@google.com4b226022011-01-11 18:32:13 +00002135
reed@google.com4e2b3d32011-04-07 14:18:59 +00002136 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002137}
2138
reed4a167172016-08-18 17:15:25 -07002139static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2140 return ((intptr_t)paint.getImageFilter() |
2141#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2142 (intptr_t)canvas->getDrawFilter() |
2143#endif
2144 (intptr_t)paint.getLooper() ) != 0;
2145}
2146
reed41af9662015-01-05 07:49:08 -08002147void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002148 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002149 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002150 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002152 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2153 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2154 SkRect tmp(r);
2155 tmp.sort();
2156
senorblanco87e066e2015-10-28 11:23:36 -07002157 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2158 return;
2159 }
2160 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002161 }
reed@google.com4b226022011-01-11 18:32:13 +00002162
reed4a167172016-08-18 17:15:25 -07002163 if (needs_autodrawlooper(this, paint)) {
2164 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002165
reed4a167172016-08-18 17:15:25 -07002166 while (iter.next()) {
2167 iter.fDevice->drawRect(iter, r, looper.paint());
2168 }
2169
2170 LOOPER_END
2171 } else {
2172 this->predrawNotify(bounds, &paint, false);
2173 SkDrawIter iter(this);
2174 while (iter.next()) {
2175 iter.fDevice->drawRect(iter, r, paint);
2176 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002177 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002178}
2179
msarett44df6512016-08-25 13:54:30 -07002180void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2181 SkRect storage;
2182 SkRect regionRect = SkRect::Make(region.getBounds());
2183 const SkRect* bounds = nullptr;
2184 if (paint.canComputeFastBounds()) {
2185 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2186 return;
2187 }
2188 bounds = &regionRect;
2189 }
2190
2191 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2192
2193 while (iter.next()) {
2194 iter.fDevice->drawRegion(iter, region, looper.paint());
2195 }
2196
2197 LOOPER_END
2198}
2199
reed41af9662015-01-05 07:49:08 -08002200void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002201 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002202 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002203 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002204 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002205 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2206 return;
2207 }
2208 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002209 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002210
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002211 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002212
2213 while (iter.next()) {
2214 iter.fDevice->drawOval(iter, oval, looper.paint());
2215 }
2216
2217 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002218}
2219
bsalomonac3aa242016-08-19 11:25:19 -07002220void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2221 SkScalar sweepAngle, bool useCenter,
2222 const SkPaint& paint) {
2223 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2224 const SkRect* bounds = nullptr;
2225 if (paint.canComputeFastBounds()) {
2226 SkRect storage;
2227 // Note we're using the entire oval as the bounds.
2228 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2229 return;
2230 }
2231 bounds = &oval;
2232 }
2233
2234 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2235
2236 while (iter.next()) {
2237 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2238 }
2239
2240 LOOPER_END
2241}
2242
reed41af9662015-01-05 07:49:08 -08002243void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002244 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002245 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002246 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002247 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002248 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2249 return;
2250 }
2251 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002252 }
2253
2254 if (rrect.isRect()) {
2255 // call the non-virtual version
2256 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002257 return;
2258 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002259 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002260 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2261 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002262 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002263
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002264 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002265
2266 while (iter.next()) {
2267 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2268 }
2269
2270 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002271}
2272
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002273void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2274 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002275 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002276 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002277 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002278 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2279 return;
2280 }
2281 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002282 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002283
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002284 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002285
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002286 while (iter.next()) {
2287 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2288 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002289
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002290 LOOPER_END
2291}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002292
reed41af9662015-01-05 07:49:08 -08002293void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002294 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002295 if (!path.isFinite()) {
2296 return;
2297 }
2298
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002299 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002300 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002301 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002302 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002303 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2304 return;
2305 }
2306 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002308
2309 const SkRect& r = path.getBounds();
2310 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002311 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002312 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002313 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002314 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002315 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002316
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002317 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318
2319 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002320 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002321 }
2322
reed@google.com4e2b3d32011-04-07 14:18:59 +00002323 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324}
2325
reed262a71b2015-12-05 13:07:27 -08002326bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002327 if (!paint.getImageFilter()) {
2328 return false;
2329 }
2330
2331 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002332 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002333 return false;
2334 }
2335
2336 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2337 // Once we can filter and the filter will return a result larger than itself, we should be
2338 // able to remove this constraint.
2339 // skbug.com/4526
2340 //
2341 SkPoint pt;
2342 ctm.mapXY(x, y, &pt);
2343 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2344 return ir.contains(fMCRec->fRasterClip.getBounds());
2345}
2346
reeda85d4d02015-05-06 12:56:48 -07002347void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002348 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002349 SkRect bounds = SkRect::MakeXYWH(x, y,
2350 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002351 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002352 SkRect tmp = bounds;
2353 if (paint) {
2354 paint->computeFastBounds(tmp, &tmp);
2355 }
2356 if (this->quickReject(tmp)) {
2357 return;
2358 }
reeda85d4d02015-05-06 12:56:48 -07002359 }
halcanary9d524f22016-03-29 09:03:52 -07002360
reeda85d4d02015-05-06 12:56:48 -07002361 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002362 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002363 paint = lazy.init();
2364 }
reed262a71b2015-12-05 13:07:27 -08002365
reeda2217ef2016-07-20 06:04:34 -07002366 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002367 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2368 *paint);
2369 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002370 special = this->getDevice()->makeSpecial(image);
2371 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002372 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002373 }
2374 }
2375
reed262a71b2015-12-05 13:07:27 -08002376 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2377
reeda85d4d02015-05-06 12:56:48 -07002378 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002379 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002380 if (special) {
2381 SkPoint pt;
2382 iter.fMatrix->mapXY(x, y, &pt);
2383 iter.fDevice->drawSpecial(iter, special.get(),
2384 SkScalarRoundToInt(pt.fX),
2385 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002386 } else {
2387 iter.fDevice->drawImage(iter, image, x, y, pnt);
2388 }
reeda85d4d02015-05-06 12:56:48 -07002389 }
halcanary9d524f22016-03-29 09:03:52 -07002390
reeda85d4d02015-05-06 12:56:48 -07002391 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002392}
2393
reed41af9662015-01-05 07:49:08 -08002394void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002395 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002396 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002397 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002398 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002399 if (paint) {
2400 paint->computeFastBounds(dst, &storage);
2401 }
2402 if (this->quickReject(storage)) {
2403 return;
2404 }
reeda85d4d02015-05-06 12:56:48 -07002405 }
2406 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002407 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002408 paint = lazy.init();
2409 }
halcanary9d524f22016-03-29 09:03:52 -07002410
senorblancoc41e7e12015-12-07 12:51:30 -08002411 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002412 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002413
reeda85d4d02015-05-06 12:56:48 -07002414 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002415 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002416 }
halcanary9d524f22016-03-29 09:03:52 -07002417
reeda85d4d02015-05-06 12:56:48 -07002418 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002419}
2420
reed41af9662015-01-05 07:49:08 -08002421void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002422 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002423 SkDEBUGCODE(bitmap.validate();)
2424
reed33366972015-10-08 09:22:02 -07002425 if (bitmap.drawsNothing()) {
2426 return;
2427 }
2428
2429 SkLazyPaint lazy;
2430 if (nullptr == paint) {
2431 paint = lazy.init();
2432 }
2433
2434 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2435
2436 SkRect storage;
2437 const SkRect* bounds = nullptr;
2438 if (paint->canComputeFastBounds()) {
2439 bitmap.getBounds(&storage);
2440 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002441 SkRect tmp = storage;
2442 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2443 return;
2444 }
2445 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446 }
reed@google.com4b226022011-01-11 18:32:13 +00002447
reeda2217ef2016-07-20 06:04:34 -07002448 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002449 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2450 *paint);
2451 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002452 special = this->getDevice()->makeSpecial(bitmap);
2453 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002454 drawAsSprite = false;
2455 }
2456 }
2457
reed262a71b2015-12-05 13:07:27 -08002458 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002459
2460 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002461 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002462 if (special) {
reed262a71b2015-12-05 13:07:27 -08002463 SkPoint pt;
2464 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002465 iter.fDevice->drawSpecial(iter, special.get(),
2466 SkScalarRoundToInt(pt.fX),
2467 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002468 } else {
2469 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2470 }
reed33366972015-10-08 09:22:02 -07002471 }
msarettfbfa2582016-08-12 08:29:08 -07002472
reed33366972015-10-08 09:22:02 -07002473 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474}
2475
reed@google.com9987ec32011-09-07 11:57:52 +00002476// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002477void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002478 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002479 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002480 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481 return;
2482 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002483
halcanary96fcdcc2015-08-27 07:41:13 -07002484 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002485 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002486 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2487 return;
2488 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002489 }
reed@google.com3d608122011-11-21 15:16:16 +00002490
reed@google.com33535f32012-09-25 15:37:50 +00002491 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002492 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002493 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002494 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002495
senorblancoc41e7e12015-12-07 12:51:30 -08002496 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002497 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002498
reed@google.com33535f32012-09-25 15:37:50 +00002499 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002500 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002501 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002502
reed@google.com33535f32012-09-25 15:37:50 +00002503 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002504}
2505
reed41af9662015-01-05 07:49:08 -08002506void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002507 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002508 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002509 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002510 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002511}
2512
reed4c21dc52015-06-25 12:32:03 -07002513void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2514 const SkPaint* paint) {
2515 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002516
halcanary96fcdcc2015-08-27 07:41:13 -07002517 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002518 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002519 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2520 return;
2521 }
reed@google.com3d608122011-11-21 15:16:16 +00002522 }
halcanary9d524f22016-03-29 09:03:52 -07002523
reed4c21dc52015-06-25 12:32:03 -07002524 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002525 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002526 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002527 }
halcanary9d524f22016-03-29 09:03:52 -07002528
senorblancoc41e7e12015-12-07 12:51:30 -08002529 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002530
reed4c21dc52015-06-25 12:32:03 -07002531 while (iter.next()) {
2532 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002533 }
halcanary9d524f22016-03-29 09:03:52 -07002534
reed4c21dc52015-06-25 12:32:03 -07002535 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002536}
2537
reed41af9662015-01-05 07:49:08 -08002538void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2539 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002540 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002541 SkDEBUGCODE(bitmap.validate();)
2542
halcanary96fcdcc2015-08-27 07:41:13 -07002543 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002544 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002545 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2546 return;
2547 }
reed4c21dc52015-06-25 12:32:03 -07002548 }
halcanary9d524f22016-03-29 09:03:52 -07002549
reed4c21dc52015-06-25 12:32:03 -07002550 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002551 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002552 paint = lazy.init();
2553 }
halcanary9d524f22016-03-29 09:03:52 -07002554
senorblancoc41e7e12015-12-07 12:51:30 -08002555 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002556
reed4c21dc52015-06-25 12:32:03 -07002557 while (iter.next()) {
2558 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2559 }
halcanary9d524f22016-03-29 09:03:52 -07002560
reed4c21dc52015-06-25 12:32:03 -07002561 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002562}
2563
msarett16882062016-08-16 09:31:08 -07002564void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2565 const SkPaint* paint) {
2566 if (nullptr == paint || paint->canComputeFastBounds()) {
2567 SkRect storage;
2568 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2569 return;
2570 }
2571 }
2572
2573 SkLazyPaint lazy;
2574 if (nullptr == paint) {
2575 paint = lazy.init();
2576 }
2577
2578 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2579
2580 while (iter.next()) {
2581 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2582 }
2583
2584 LOOPER_END
2585}
2586
2587void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2588 const SkRect& dst, const SkPaint* paint) {
2589 if (nullptr == paint || paint->canComputeFastBounds()) {
2590 SkRect storage;
2591 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2592 return;
2593 }
2594 }
2595
2596 SkLazyPaint lazy;
2597 if (nullptr == paint) {
2598 paint = lazy.init();
2599 }
2600
2601 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2602
2603 while (iter.next()) {
2604 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2605 }
2606
2607 LOOPER_END
2608}
2609
reed@google.comf67e4cf2011-03-15 20:56:58 +00002610class SkDeviceFilteredPaint {
2611public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002612 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002613 uint32_t filteredFlags = device->filterTextFlags(paint);
2614 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002615 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002616 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002617 fPaint = newPaint;
2618 } else {
2619 fPaint = &paint;
2620 }
2621 }
2622
reed@google.comf67e4cf2011-03-15 20:56:58 +00002623 const SkPaint& paint() const { return *fPaint; }
2624
2625private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002626 const SkPaint* fPaint;
2627 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002628};
2629
bungeman@google.com52c748b2011-08-22 21:30:43 +00002630void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2631 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002632 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002633 draw.fDevice->drawRect(draw, r, paint);
2634 } else {
2635 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002636 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002637 draw.fDevice->drawRect(draw, r, p);
2638 }
2639}
2640
2641void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2642 const char text[], size_t byteLength,
2643 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002644 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002645
2646 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002647 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002648 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002649 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002650 return;
2651 }
2652
2653 SkScalar width = 0;
2654 SkPoint start;
2655
2656 start.set(0, 0); // to avoid warning
2657 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2658 SkPaint::kStrikeThruText_Flag)) {
2659 width = paint.measureText(text, byteLength);
2660
2661 SkScalar offsetX = 0;
2662 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2663 offsetX = SkScalarHalf(width);
2664 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2665 offsetX = width;
2666 }
2667 start.set(x - offsetX, y);
2668 }
2669
2670 if (0 == width) {
2671 return;
2672 }
2673
2674 uint32_t flags = paint.getFlags();
2675
2676 if (flags & (SkPaint::kUnderlineText_Flag |
2677 SkPaint::kStrikeThruText_Flag)) {
2678 SkScalar textSize = paint.getTextSize();
2679 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2680 SkRect r;
2681
2682 r.fLeft = start.fX;
2683 r.fRight = start.fX + width;
2684
2685 if (flags & SkPaint::kUnderlineText_Flag) {
2686 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2687 start.fY);
2688 r.fTop = offset;
2689 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002690 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002691 }
2692 if (flags & SkPaint::kStrikeThruText_Flag) {
2693 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2694 start.fY);
2695 r.fTop = offset;
2696 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002697 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002698 }
2699 }
2700}
2701
reed@google.come0d9ce82014-04-23 04:00:17 +00002702void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2703 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002704 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002705
2706 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002707 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002708 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002709 DrawTextDecorations(iter, dfp.paint(),
2710 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711 }
2712
reed@google.com4e2b3d32011-04-07 14:18:59 +00002713 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714}
2715
reed@google.come0d9ce82014-04-23 04:00:17 +00002716void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2717 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002718 SkPoint textOffset = SkPoint::Make(0, 0);
2719
halcanary96fcdcc2015-08-27 07:41:13 -07002720 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002721
reed@android.com8a1c16f2008-12-17 15:59:43 +00002722 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002723 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002724 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002725 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002727
reed@google.com4e2b3d32011-04-07 14:18:59 +00002728 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002729}
2730
reed@google.come0d9ce82014-04-23 04:00:17 +00002731void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2732 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002733
2734 SkPoint textOffset = SkPoint::Make(0, constY);
2735
halcanary96fcdcc2015-08-27 07:41:13 -07002736 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002737
reed@android.com8a1c16f2008-12-17 15:59:43 +00002738 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002739 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002740 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002741 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002743
reed@google.com4e2b3d32011-04-07 14:18:59 +00002744 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002745}
2746
reed@google.come0d9ce82014-04-23 04:00:17 +00002747void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2748 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002749 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002750
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 while (iter.next()) {
2752 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002753 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002754 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002755
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002756 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002757}
2758
reed45561a02016-07-07 12:47:17 -07002759void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2760 const SkRect* cullRect, const SkPaint& paint) {
2761 if (cullRect && this->quickReject(*cullRect)) {
2762 return;
2763 }
2764
2765 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2766
2767 while (iter.next()) {
2768 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2769 }
2770
2771 LOOPER_END
2772}
2773
fmalita00d5c2c2014-08-21 08:53:26 -07002774void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2775 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002776
fmalita85d5eb92015-03-04 11:20:12 -08002777 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002778 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002779 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002780 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002781 SkRect tmp;
2782 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2783 return;
2784 }
2785 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002786 }
2787
fmalita024f9962015-03-03 19:08:17 -08002788 // We cannot filter in the looper as we normally do, because the paint is
2789 // incomplete at this point (text-related attributes are embedded within blob run paints).
2790 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002791 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002792
fmalita85d5eb92015-03-04 11:20:12 -08002793 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002794
fmalitaaa1b9122014-08-28 14:32:24 -07002795 while (iter.next()) {
2796 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002797 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002798 }
2799
fmalitaaa1b9122014-08-28 14:32:24 -07002800 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002801
2802 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002803}
2804
reed@google.come0d9ce82014-04-23 04:00:17 +00002805// These will become non-virtual, so they always call the (virtual) onDraw... method
2806void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2807 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002808 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002809 if (byteLength) {
2810 this->onDrawText(text, byteLength, x, y, paint);
2811 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002812}
2813void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2814 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002816 if (byteLength) {
2817 this->onDrawPosText(text, byteLength, pos, paint);
2818 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002819}
2820void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2821 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002822 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002823 if (byteLength) {
2824 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2825 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002826}
2827void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2828 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002829 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002830 if (byteLength) {
2831 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2832 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002833}
reed45561a02016-07-07 12:47:17 -07002834void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2835 const SkRect* cullRect, const SkPaint& paint) {
2836 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2837 if (byteLength) {
2838 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2839 }
2840}
fmalita00d5c2c2014-08-21 08:53:26 -07002841void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2842 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002843 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002844 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002845 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002846}
reed@google.come0d9ce82014-04-23 04:00:17 +00002847
reed41af9662015-01-05 07:49:08 -08002848void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2849 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002850 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002851 const uint16_t indices[], int indexCount,
2852 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002853 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002854 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002855
reed@android.com8a1c16f2008-12-17 15:59:43 +00002856 while (iter.next()) {
2857 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002858 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002859 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002860 }
reed@google.com4b226022011-01-11 18:32:13 +00002861
reed@google.com4e2b3d32011-04-07 14:18:59 +00002862 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002863}
2864
dandovb3c9d1c2014-08-12 08:34:29 -07002865void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002866 const SkPoint texCoords[4], SkBlendMode bmode,
2867 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002868 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002869 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002870 return;
2871 }
mtklein6cfa73a2014-08-13 13:33:49 -07002872
Mike Reedfaba3712016-11-03 14:45:31 -04002873 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002874}
2875
2876void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002877 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002878 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002879 // Since a patch is always within the convex hull of the control points, we discard it when its
2880 // bounding rectangle is completely outside the current clip.
2881 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002882 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002883 if (this->quickReject(bounds)) {
2884 return;
2885 }
mtklein6cfa73a2014-08-13 13:33:49 -07002886
halcanary96fcdcc2015-08-27 07:41:13 -07002887 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002888
dandovecfff212014-08-04 10:02:00 -07002889 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002890 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002891 }
mtklein6cfa73a2014-08-13 13:33:49 -07002892
dandovecfff212014-08-04 10:02:00 -07002893 LOOPER_END
2894}
2895
reeda8db7282015-07-07 10:22:31 -07002896void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002897 RETURN_ON_NULL(dr);
2898 if (x || y) {
2899 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2900 this->onDrawDrawable(dr, &matrix);
2901 } else {
2902 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002903 }
2904}
2905
reeda8db7282015-07-07 10:22:31 -07002906void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002907 RETURN_ON_NULL(dr);
2908 if (matrix && matrix->isIdentity()) {
2909 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002910 }
reede3b38ce2016-01-08 09:18:44 -08002911 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002912}
2913
2914void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002915 // drawable bounds are no longer reliable (e.g. android displaylist)
2916 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002917 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002918}
2919
reed71c3c762015-06-24 10:29:17 -07002920void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002921 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002922 const SkRect* cull, const SkPaint* paint) {
2923 if (cull && this->quickReject(*cull)) {
2924 return;
2925 }
2926
2927 SkPaint pnt;
2928 if (paint) {
2929 pnt = *paint;
2930 }
halcanary9d524f22016-03-29 09:03:52 -07002931
halcanary96fcdcc2015-08-27 07:41:13 -07002932 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002933 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002934 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002935 }
2936 LOOPER_END
2937}
2938
reedf70b5312016-03-04 16:36:20 -08002939void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2940 SkASSERT(key);
2941
2942 SkPaint paint;
2943 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2944 while (iter.next()) {
2945 iter.fDevice->drawAnnotation(iter, rect, key, value);
2946 }
2947 LOOPER_END
2948}
2949
reed@android.com8a1c16f2008-12-17 15:59:43 +00002950//////////////////////////////////////////////////////////////////////////////
2951// These methods are NOT virtual, and therefore must call back into virtual
2952// methods, rather than actually drawing themselves.
2953//////////////////////////////////////////////////////////////////////////////
2954
reed374772b2016-10-05 17:33:02 -07002955void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002956 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002957 SkPaint paint;
2958
2959 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002960 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002961 this->drawPaint(paint);
2962}
2963
reed374772b2016-10-05 17:33:02 -07002964void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002965 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002966 SkPaint paint;
2967
2968 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002969 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002970 this->drawPaint(paint);
2971}
2972
2973void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002974 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002975 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002976
reed@android.com8a1c16f2008-12-17 15:59:43 +00002977 pt.set(x, y);
2978 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2979}
2980
2981void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002982 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002983 SkPoint pt;
2984 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002985
reed@android.com8a1c16f2008-12-17 15:59:43 +00002986 pt.set(x, y);
2987 paint.setColor(color);
2988 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2989}
2990
2991void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2992 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002993 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002994 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002995
reed@android.com8a1c16f2008-12-17 15:59:43 +00002996 pts[0].set(x0, y0);
2997 pts[1].set(x1, y1);
2998 this->drawPoints(kLines_PointMode, 2, pts, paint);
2999}
3000
3001void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3002 SkScalar right, SkScalar bottom,
3003 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003004 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003005 SkRect r;
3006
3007 r.set(left, top, right, bottom);
3008 this->drawRect(r, paint);
3009}
3010
3011void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3012 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003013 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003014 if (radius < 0) {
3015 radius = 0;
3016 }
3017
3018 SkRect r;
3019 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003020 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003021}
3022
3023void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3024 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003025 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003026 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003027 SkRRect rrect;
3028 rrect.setRectXY(r, rx, ry);
3029 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003030 } else {
3031 this->drawRect(r, paint);
3032 }
3033}
3034
reed@android.com8a1c16f2008-12-17 15:59:43 +00003035void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3036 SkScalar sweepAngle, bool useCenter,
3037 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003038 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003039 if (oval.isEmpty() || !sweepAngle) {
3040 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003041 }
bsalomon21af9ca2016-08-25 12:29:23 -07003042 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003043}
3044
3045void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3046 const SkPath& path, SkScalar hOffset,
3047 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003048 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003049 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003050
reed@android.com8a1c16f2008-12-17 15:59:43 +00003051 matrix.setTranslate(hOffset, vOffset);
3052 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3053}
3054
reed@android.comf76bacf2009-05-13 14:00:33 +00003055///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003056
3057/**
3058 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3059 * against the playback cost of recursing into the subpicture to get at its actual ops.
3060 *
3061 * For now we pick a conservatively small value, though measurement (and other heuristics like
3062 * the type of ops contained) may justify changing this value.
3063 */
3064#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003065
reedd5fa1a42014-08-09 11:08:05 -07003066void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003067 RETURN_ON_NULL(picture);
3068
reed1c2c4412015-04-30 13:09:24 -07003069 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003070 if (matrix && matrix->isIdentity()) {
3071 matrix = nullptr;
3072 }
3073 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3074 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3075 picture->playback(this);
3076 } else {
3077 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003078 }
3079}
robertphillips9b14f262014-06-04 05:40:44 -07003080
reedd5fa1a42014-08-09 11:08:05 -07003081void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3082 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003083 if (!paint || paint->canComputeFastBounds()) {
3084 SkRect bounds = picture->cullRect();
3085 if (paint) {
3086 paint->computeFastBounds(bounds, &bounds);
3087 }
3088 if (matrix) {
3089 matrix->mapRect(&bounds);
3090 }
3091 if (this->quickReject(bounds)) {
3092 return;
3093 }
3094 }
3095
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003096 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003097 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003098}
3099
vjiaoblack95302da2016-07-21 10:25:54 -07003100#ifdef SK_EXPERIMENTAL_SHADOWING
3101void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3102 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003103 const SkPaint* paint,
3104 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003105 RETURN_ON_NULL(picture);
3106
3107 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3108
vjiaoblacke6f5d562016-08-25 06:30:23 -07003109 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003110}
3111
3112void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3113 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003114 const SkPaint* paint,
3115 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003116 if (!paint || paint->canComputeFastBounds()) {
3117 SkRect bounds = picture->cullRect();
3118 if (paint) {
3119 paint->computeFastBounds(bounds, &bounds);
3120 }
3121 if (matrix) {
3122 matrix->mapRect(&bounds);
3123 }
3124 if (this->quickReject(bounds)) {
3125 return;
3126 }
3127 }
3128
3129 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3130
vjiaoblacke6f5d562016-08-25 06:30:23 -07003131 sk_sp<SkImage> povDepthMap;
3132 sk_sp<SkImage> diffuseMap;
3133
vjiaoblack904527d2016-08-09 09:32:09 -07003134 // povDepthMap
3135 {
3136 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003137 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3138 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003139 sk_sp<SkLights> povLight = builder.finish();
3140
3141 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3142 picture->cullRect().height(),
3143 kBGRA_8888_SkColorType,
3144 kOpaque_SkAlphaType);
3145
3146 // Create a new surface (that matches the backend of canvas)
3147 // to create the povDepthMap
3148 sk_sp<SkSurface> surf(this->makeSurface(info));
3149
3150 // Wrap another SPFCanvas around the surface
3151 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3152 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3153
3154 // set the depth map canvas to have the light as the user's POV
3155 depthMapCanvas->setLights(std::move(povLight));
3156
3157 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003158 povDepthMap = surf->makeImageSnapshot();
3159 }
3160
3161 // diffuseMap
3162 {
3163 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3164 picture->cullRect().height(),
3165 kBGRA_8888_SkColorType,
3166 kOpaque_SkAlphaType);
3167
3168 sk_sp<SkSurface> surf(this->makeSurface(info));
3169 surf->getCanvas()->drawPicture(picture);
3170
3171 diffuseMap = surf->makeImageSnapshot();
3172 }
vjiaoblack904527d2016-08-09 09:32:09 -07003173
3174 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3175 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003176 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3177 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003178
3179 // TODO: pass the depth to the shader in vertices, or uniforms
3180 // so we don't have to render depth and color separately
3181 for (int i = 0; i < fLights->numLights(); ++i) {
3182 // skip over ambient lights; they don't cast shadows
3183 // lights that have shadow maps do not need updating (because lights are immutable)
3184 sk_sp<SkImage> depthMap;
3185 SkISize shMapSize;
3186
3187 if (fLights->light(i).getShadowMap() != nullptr) {
3188 continue;
3189 }
3190
3191 if (fLights->light(i).isRadial()) {
3192 shMapSize.fHeight = 1;
3193 shMapSize.fWidth = (int) picture->cullRect().width();
3194
3195 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3196 kBGRA_8888_SkColorType,
3197 kOpaque_SkAlphaType);
3198
3199 // Create new surface (that matches the backend of canvas)
3200 // for each shadow map
3201 sk_sp<SkSurface> surf(this->makeSurface(info));
3202
3203 // Wrap another SPFCanvas around the surface
3204 SkCanvas* depthMapCanvas = surf->getCanvas();
3205
3206 SkLights::Builder builder;
3207 builder.add(fLights->light(i));
3208 sk_sp<SkLights> curLight = builder.finish();
3209
3210 sk_sp<SkShader> shadowMapShader;
3211 shadowMapShader = SkRadialShadowMapShader::Make(
3212 povDepthShader, curLight,
3213 (int) picture->cullRect().width(),
3214 (int) picture->cullRect().height());
3215
3216 SkPaint shadowMapPaint;
3217 shadowMapPaint.setShader(std::move(shadowMapShader));
3218
3219 depthMapCanvas->setLights(curLight);
3220
3221 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3222 diffuseMap->height()),
3223 shadowMapPaint);
3224
3225 depthMap = surf->makeImageSnapshot();
3226
3227 } else {
3228 // TODO: compute the correct size of the depth map from the light properties
3229 // TODO: maybe add a kDepth_8_SkColorType
3230 // TODO: find actual max depth of picture
3231 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3232 fLights->light(i), 255,
3233 (int) picture->cullRect().width(),
3234 (int) picture->cullRect().height());
3235
3236 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3237 kBGRA_8888_SkColorType,
3238 kOpaque_SkAlphaType);
3239
3240 // Create a new surface (that matches the backend of canvas)
3241 // for each shadow map
3242 sk_sp<SkSurface> surf(this->makeSurface(info));
3243
3244 // Wrap another SPFCanvas around the surface
3245 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3246 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3247 depthMapCanvas->setShadowParams(params);
3248
3249 // set the depth map canvas to have the light we're drawing.
3250 SkLights::Builder builder;
3251 builder.add(fLights->light(i));
3252 sk_sp<SkLights> curLight = builder.finish();
3253 depthMapCanvas->setLights(std::move(curLight));
3254
3255 depthMapCanvas->drawPicture(picture);
3256 depthMap = surf->makeImageSnapshot();
3257 }
3258
3259 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3260 fLights->light(i).setShadowMap(std::move(depthMap));
3261 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3262 // we blur the variance map
3263 SkPaint blurPaint;
3264 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3265 params.fShadowRadius, nullptr));
3266
3267 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3268 kBGRA_8888_SkColorType,
3269 kOpaque_SkAlphaType);
3270
3271 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3272
3273 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3274
3275 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3276 }
3277 }
3278
3279 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003280 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3281 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003282 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003283 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003284 diffuseMap->height(),
3285 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003286
3287 shadowPaint.setShader(shadowShader);
3288
3289 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003290}
3291#endif
3292
reed@android.com8a1c16f2008-12-17 15:59:43 +00003293///////////////////////////////////////////////////////////////////////////////
3294///////////////////////////////////////////////////////////////////////////////
3295
reed3aafe112016-08-18 12:45:34 -07003296SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003297 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003298
3299 SkASSERT(canvas);
3300
reed3aafe112016-08-18 12:45:34 -07003301 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003302 fDone = !fImpl->next();
3303}
3304
3305SkCanvas::LayerIter::~LayerIter() {
3306 fImpl->~SkDrawIter();
3307}
3308
3309void SkCanvas::LayerIter::next() {
3310 fDone = !fImpl->next();
3311}
3312
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003313SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003314 return fImpl->getDevice();
3315}
3316
3317const SkMatrix& SkCanvas::LayerIter::matrix() const {
3318 return fImpl->getMatrix();
3319}
3320
3321const SkPaint& SkCanvas::LayerIter::paint() const {
3322 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003323 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003324 paint = &fDefaultPaint;
3325 }
3326 return *paint;
3327}
3328
reed1e7f5e72016-04-27 07:49:17 -07003329const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003330int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3331int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003332
3333///////////////////////////////////////////////////////////////////////////////
3334
fmalitac3b589a2014-06-05 12:40:07 -07003335SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003336
3337///////////////////////////////////////////////////////////////////////////////
3338
3339static bool supported_for_raster_canvas(const SkImageInfo& info) {
3340 switch (info.alphaType()) {
3341 case kPremul_SkAlphaType:
3342 case kOpaque_SkAlphaType:
3343 break;
3344 default:
3345 return false;
3346 }
3347
3348 switch (info.colorType()) {
3349 case kAlpha_8_SkColorType:
3350 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003351 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003352 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003353 break;
3354 default:
3355 return false;
3356 }
3357
3358 return true;
3359}
3360
Mike Reed5df49342016-11-12 08:06:55 -06003361std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3362 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003363 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003364 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003365 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003366
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003367 SkBitmap bitmap;
3368 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003369 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003370 }
Mike Reed5df49342016-11-12 08:06:55 -06003371 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003372}
reedd5fa1a42014-08-09 11:08:05 -07003373
3374///////////////////////////////////////////////////////////////////////////////
3375
3376SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003377 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003378 : fCanvas(canvas)
3379 , fSaveCount(canvas->getSaveCount())
3380{
bsalomon49f085d2014-09-05 13:34:00 -07003381 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003382 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003383 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003384 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003385 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003386 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003387 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003388 canvas->save();
3389 }
mtklein6cfa73a2014-08-13 13:33:49 -07003390
bsalomon49f085d2014-09-05 13:34:00 -07003391 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003392 canvas->concat(*matrix);
3393 }
3394}
3395
3396SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3397 fCanvas->restoreToCount(fSaveCount);
3398}
reede8f30622016-03-23 18:59:25 -07003399
Florin Malitaee424ac2016-12-01 12:47:59 -05003400///////////////////////////////////////////////////////////////////////////////
3401
3402SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3403 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3404
Florin Malita439ace92016-12-02 12:05:41 -05003405SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3406 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3407
Florin Malitaee424ac2016-12-01 12:47:59 -05003408SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3409 (void)this->INHERITED::getSaveLayerStrategy(rec);
3410 return kNoLayer_SaveLayerStrategy;
3411}
3412
3413///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003414
reed73603f32016-09-20 08:42:38 -07003415static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3416static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3417static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3418static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3419static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3420static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003421
3422///////////////////////////////////////////////////////////////////////////////////////////////////
3423
3424SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3425 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3426 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3427 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3428 SkIPoint origin = dev->getOrigin();
3429 SkMatrix ctm = this->getTotalMatrix();
3430 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3431
3432 SkIRect clip = fMCRec->fRasterClip.getBounds();
3433 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003434 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003435 clip.setEmpty();
3436 }
3437
3438 fAllocator->updateHandle(handle, ctm, clip);
3439 return handle;
3440 }
3441 return nullptr;
3442}
3443
3444static bool install(SkBitmap* bm, const SkImageInfo& info,
3445 const SkRasterHandleAllocator::Rec& rec) {
3446 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3447 rec.fReleaseProc, rec.fReleaseCtx);
3448}
3449
3450SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3451 SkBitmap* bm) {
3452 SkRasterHandleAllocator::Rec rec;
3453 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3454 return nullptr;
3455 }
3456 return rec.fHandle;
3457}
3458
3459std::unique_ptr<SkCanvas>
3460SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3461 const SkImageInfo& info, const Rec* rec) {
3462 if (!alloc || !supported_for_raster_canvas(info)) {
3463 return nullptr;
3464 }
3465
3466 SkBitmap bm;
3467 Handle hndl;
3468
3469 if (rec) {
3470 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3471 } else {
3472 hndl = alloc->allocBitmap(info, &bm);
3473 }
3474 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3475}