blob: cb76051add5d48ac5d1d091e3fd0016f155fbbfd [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
bungemand3ebb482015-08-05 13:57:49 -07008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080018#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070019#include "SkImageFilter.h"
20#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070021#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060022#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050025#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070026#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070027#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070028#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000029#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070030#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000031#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080032#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000033#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070034#include "SkShadowPaintFilterCanvas.h"
35#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000036#include "SkSmallAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000047#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070048#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050051#include "SkClipOpPriv.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052
reede3b38ce2016-01-08 09:18:44 -080053#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
54
reedc83a2972015-07-16 07:40:45 -070055/*
56 * Return true if the drawing this rect would hit every pixels in the canvas.
57 *
58 * Returns false if
59 * - rect does not contain the canvas' bounds
60 * - paint is not fill
61 * - paint would blur or otherwise change the coverage of the rect
62 */
63bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
64 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070065 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
66 (int)kNone_ShaderOverrideOpacity,
67 "need_matching_enums0");
68 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
69 (int)kOpaque_ShaderOverrideOpacity,
70 "need_matching_enums1");
71 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
72 (int)kNotOpaque_ShaderOverrideOpacity,
73 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070074
75 const SkISize size = this->getBaseLayerSize();
76 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
77 if (!this->getClipStack()->quickContains(bounds)) {
78 return false;
79 }
80
81 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070082 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070083 return false; // conservative
84 }
halcanaryc5769b22016-08-10 07:13:21 -070085
86 SkRect devRect;
87 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
88 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070089 return false;
90 }
91 }
92
93 if (paint) {
94 SkPaint::Style paintStyle = paint->getStyle();
95 if (!(paintStyle == SkPaint::kFill_Style ||
96 paintStyle == SkPaint::kStrokeAndFill_Style)) {
97 return false;
98 }
99 if (paint->getMaskFilter() || paint->getLooper()
100 || paint->getPathEffect() || paint->getImageFilter()) {
101 return false; // conservative
102 }
103 }
104 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
105}
106
107///////////////////////////////////////////////////////////////////////////////////////////////////
108
reedd990e2f2014-12-22 11:58:30 -0800109static bool gIgnoreSaveLayerBounds;
110void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
111 gIgnoreSaveLayerBounds = ignore;
112}
113bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
114 return gIgnoreSaveLayerBounds;
115}
116
reed0acf1b42014-12-22 16:12:38 -0800117static bool gTreatSpriteAsBitmap;
118void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
119 gTreatSpriteAsBitmap = spriteAsBitmap;
120}
121bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
122 return gTreatSpriteAsBitmap;
123}
124
reed@google.comda17f752012-08-16 18:27:05 +0000125// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126//#define SK_TRACE_SAVERESTORE
127
128#ifdef SK_TRACE_SAVERESTORE
129 static int gLayerCounter;
130 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
131 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
132
133 static int gRecCounter;
134 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
135 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
136
137 static int gCanvasCounter;
138 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
139 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
140#else
141 #define inc_layer()
142 #define dec_layer()
143 #define inc_rec()
144 #define dec_rec()
145 #define inc_canvas()
146 #define dec_canvas()
147#endif
148
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000149typedef SkTLazy<SkPaint> SkLazyPaint;
150
reedc83a2972015-07-16 07:40:45 -0700151void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000152 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700153 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
154 ? SkSurface::kDiscard_ContentChangeMode
155 : SkSurface::kRetain_ContentChangeMode);
156 }
157}
158
159void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
160 ShaderOverrideOpacity overrideOpacity) {
161 if (fSurfaceBase) {
162 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
163 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
164 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
165 // and therefore we don't care which mode we're in.
166 //
167 if (fSurfaceBase->outstandingImageSnapshot()) {
168 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
169 mode = SkSurface::kDiscard_ContentChangeMode;
170 }
171 }
172 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000173 }
174}
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000178/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 The clip/matrix/proc are fields that reflect the top of the save/restore
180 stack. Whenever the canvas changes, it marks a dirty flag, and then before
181 these are used (assuming we're not on a layer) we rebuild these cache
182 values: they reflect the top of the save stack, but translated and clipped
183 by the device's XY offset and bitmap-bounds.
184*/
185struct DeviceCM {
186 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000187 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000188 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000189 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700190 const SkMatrix* fMatrix;
191 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700192 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193
reed96e657d2015-03-10 17:30:07 -0700194 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700195 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700196 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700197 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700198 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700199 {
reed2c9e2002016-07-25 08:05:22 -0700200 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000201 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700202 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000203 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000205 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700206 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700207 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000208 }
reed@google.com4b226022011-01-11 18:32:13 +0000209
mtkleinfeaadee2015-04-08 11:25:48 -0700210 void reset(const SkIRect& bounds) {
211 SkASSERT(!fPaint);
212 SkASSERT(!fNext);
213 SkASSERT(fDevice);
214 fClip.setRect(bounds);
215 }
216
reed@google.com045e62d2011-10-24 12:19:46 +0000217 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700218 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000219 int x = fDevice->getOrigin().x();
220 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 int width = fDevice->width();
222 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000223
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 if ((x | y) == 0) {
225 fMatrix = &totalMatrix;
226 fClip = totalClip;
227 } else {
228 fMatrixStorage = totalMatrix;
229 fMatrixStorage.postTranslate(SkIntToScalar(-x),
230 SkIntToScalar(-y));
231 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 totalClip.translate(-x, -y, &fClip);
234 }
235
reed@google.com045e62d2011-10-24 12:19:46 +0000236 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
238 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000241 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 SkRegion::kDifference_Op);
243 }
reed@google.com4b226022011-01-11 18:32:13 +0000244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245#ifdef SK_DEBUG
246 if (!fClip.isEmpty()) {
247 SkIRect deviceR;
248 deviceR.set(0, 0, width, height);
249 SkASSERT(deviceR.contains(fClip.getBounds()));
250 }
251#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000252 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253};
254
255/* This is the record we keep for each save/restore level in the stack.
256 Since a level optionally copies the matrix and/or stack, we have pointers
257 for these fields. If the value is copied for this level, the copy is
258 stored in the ...Storage field, and the pointer points to that. If the
259 value is not copied for this level, we ignore ...Storage, and just point
260 at the corresponding value in the previous level in the stack.
261*/
262class SkCanvas::MCRec {
263public:
reed1f836ee2014-07-07 07:49:34 -0700264 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700265 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 /* If there are any layers in the stack, this points to the top-most
267 one that is at or below this level in the stack (so we know what
268 bitmap/device to draw into from this level. This value is NOT
269 reference counted, since the real owner is either our fLayer field,
270 or a previous one in a lower level.)
271 */
reed2ff1fce2014-12-11 07:07:37 -0800272 DeviceCM* fTopLayer;
273 SkRasterClip fRasterClip;
274 SkMatrix fMatrix;
275 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276
vjiaoblacke5de1302016-07-13 14:05:28 -0700277 // This is the current cumulative depth (aggregate of all done translateZ calls)
278 SkScalar fCurDrawDepth;
279
reedd9544982014-09-09 18:46:22 -0700280 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700281 fFilter = nullptr;
282 fLayer = nullptr;
283 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800284 fMatrix.reset();
285 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700286 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700287
reedd9544982014-09-09 18:46:22 -0700288 // don't bother initializing fNext
289 inc_rec();
290 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700291 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
292 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700293 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700294 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700295 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800296 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700297
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 // don't bother initializing fNext
299 inc_rec();
300 }
301 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000302 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700303 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 dec_rec();
305 }
mtkleinfeaadee2015-04-08 11:25:48 -0700306
307 void reset(const SkIRect& bounds) {
308 SkASSERT(fLayer);
309 SkASSERT(fDeferredSaveCount == 0);
310
311 fMatrix.reset();
312 fRasterClip.setRect(bounds);
313 fLayer->reset(bounds);
314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315};
316
reed02f9ed72016-09-06 09:06:18 -0700317static SkIRect compute_device_bounds(SkBaseDevice* device) {
318 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
319 device->width(), device->height());
320}
321
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322class SkDrawIter : public SkDraw {
323public:
reed3aafe112016-08-18 12:45:34 -0700324 SkDrawIter(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 canvas->updateDeviceCMCache();
326
bungeman6bd52842016-10-27 09:30:08 -0700327 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700329
330 fMultiDeviceCS = nullptr;
331 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700332 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700333 fMultiDeviceCS->save();
334 }
335 }
336
337 ~SkDrawIter() {
338 if (fMultiDeviceCS) {
339 fMultiDeviceCS->restore();
340 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 }
reed@google.com4b226022011-01-11 18:32:13 +0000342
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700344 if (fMultiDeviceCS && fDevice) {
345 // remove the previous device's bounds
Mike Reedc1f77742016-12-09 09:00:50 -0500346 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), kDifference_SkClipOp);
reed02f9ed72016-09-06 09:06:18 -0700347 }
348
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700350 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
351 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 }
353
reed@google.comf68c5e22012-02-24 16:38:58 +0000354 const DeviceCM* rec = fCurrLayer;
355 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356
357 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000358 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700360 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700361 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700362 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000364 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365
366 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700367 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000368
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 return true;
370 }
371 return false;
372 }
reed@google.com4b226022011-01-11 18:32:13 +0000373
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000374 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700375 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000376 int getX() const { return fDevice->getOrigin().x(); }
377 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000380
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382 const DeviceCM* fCurrLayer;
383 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700384 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385
386 typedef SkDraw INHERITED;
387};
388
389/////////////////////////////////////////////////////////////////////////////
390
reeddbc3cef2015-04-29 12:18:57 -0700391static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
392 return lazy->isValid() ? lazy->get() : lazy->set(orig);
393}
394
395/**
396 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700397 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700398 */
reedd053ce92016-03-22 10:17:23 -0700399static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700400 SkImageFilter* imgf = paint.getImageFilter();
401 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700402 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700403 }
404
reedd053ce92016-03-22 10:17:23 -0700405 SkColorFilter* imgCFPtr;
406 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700407 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700408 }
reedd053ce92016-03-22 10:17:23 -0700409 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700410
411 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700412 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700413 // there is no existing paint colorfilter, so we can just return the imagefilter's
414 return imgCF;
415 }
416
417 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
418 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700419 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700420}
421
senorblanco87e066e2015-10-28 11:23:36 -0700422/**
423 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
424 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
425 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
426 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
427 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
428 * conservative "effective" bounds based on the settings in the paint... with one exception. This
429 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
430 * deliberately ignored.
431 */
432static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
433 const SkRect& rawBounds,
434 SkRect* storage) {
435 SkPaint tmpUnfiltered(paint);
436 tmpUnfiltered.setImageFilter(nullptr);
437 if (tmpUnfiltered.canComputeFastBounds()) {
438 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
439 } else {
440 return rawBounds;
441 }
442}
443
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444class AutoDrawLooper {
445public:
senorblanco87e066e2015-10-28 11:23:36 -0700446 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
447 // paint. It's used to determine the size of the offscreen layer for filters.
448 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700449 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700450 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000451 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800452#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800454#else
455 fFilter = nullptr;
456#endif
reed4a8126e2014-09-22 07:29:03 -0700457 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000458 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700459 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000460 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000461
reedd053ce92016-03-22 10:17:23 -0700462 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700463 if (simplifiedCF) {
464 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700465 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700466 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700467 fPaint = paint;
468 }
469
470 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700471 /**
472 * We implement ImageFilters for a given draw by creating a layer, then applying the
473 * imagefilter to the pixels of that layer (its backing surface/image), and then
474 * we call restore() to xfer that layer to the main canvas.
475 *
476 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
477 * 2. Generate the src pixels:
478 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
479 * return (fPaint). We then draw the primitive (using srcover) into a cleared
480 * buffer/surface.
481 * 3. Restore the layer created in #1
482 * The imagefilter is passed the buffer/surface from the layer (now filled with the
483 * src pixels of the primitive). It returns a new "filtered" buffer, which we
484 * draw onto the previous layer using the xfermode from the original paint.
485 */
reed@google.com8926b162012-03-23 15:36:36 +0000486 SkPaint tmp;
Mike Reed5e257172016-11-01 11:22:05 -0400487 tmp.setImageFilter(sk_ref_sp(fPaint->getImageFilter()));
reed374772b2016-10-05 17:33:02 -0700488 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700489 SkRect storage;
490 if (rawBounds) {
491 // Make rawBounds include all paint outsets except for those due to image filters.
492 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
493 }
reedbfd5f172016-01-07 11:28:08 -0800494 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700495 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700496 fTempLayerForImageFilter = true;
497 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000498 }
499
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000500 if (SkDrawLooper* looper = paint.getLooper()) {
herbbf6d80a2016-11-15 06:26:56 -0800501 fLooperContext = fLooperContextAllocator.createWithIniter(
502 looper->contextSize(),
503 [&](void* buffer) {
504 return looper->createContext(canvas, buffer);
505 });
reed@google.com129ec222012-05-15 13:24:09 +0000506 fIsSimple = false;
507 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700508 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000509 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700510 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000511 }
512 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000513
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700515 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000516 fCanvas->internalRestore();
517 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000518 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000520
reed@google.com4e2b3d32011-04-07 14:18:59 +0000521 const SkPaint& paint() const {
522 SkASSERT(fPaint);
523 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000525
reed@google.com129ec222012-05-15 13:24:09 +0000526 bool next(SkDrawFilter::Type drawType) {
527 if (fDone) {
528 return false;
529 } else if (fIsSimple) {
530 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000531 return !fPaint->nothingToDraw();
532 } else {
533 return this->doNext(drawType);
534 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000535 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000536
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537private:
reeddbc3cef2015-04-29 12:18:57 -0700538 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
539 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000540 SkCanvas* fCanvas;
541 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000542 SkDrawFilter* fFilter;
543 const SkPaint* fPaint;
544 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700545 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000546 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000547 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000548 SkDrawLooper::Context* fLooperContext;
549 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000550
551 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552};
553
reed@google.com129ec222012-05-15 13:24:09 +0000554bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700555 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000556 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700557 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000558
reeddbc3cef2015-04-29 12:18:57 -0700559 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
560 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000561
reed5c476fb2015-04-20 08:04:21 -0700562 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700563 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700564 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000565 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000566
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000567 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000568 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000569 return false;
570 }
571 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000572 if (!fFilter->filter(paint, drawType)) {
573 fDone = true;
574 return false;
575 }
halcanary96fcdcc2015-08-27 07:41:13 -0700576 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000577 // no looper means we only draw once
578 fDone = true;
579 }
580 }
581 fPaint = paint;
582
583 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000584 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000585 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000586 }
587
588 // call this after any possible paint modifiers
589 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700590 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000591 return false;
592 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000593 return true;
594}
595
reed@android.com8a1c16f2008-12-17 15:59:43 +0000596////////// macros to place around the internal draw calls //////////////////
597
reed3aafe112016-08-18 12:45:34 -0700598#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
599 this->predrawNotify(); \
600 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
601 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800602 SkDrawIter iter(this);
603
604
reed@google.com8926b162012-03-23 15:36:36 +0000605#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000606 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700607 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000608 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000609 SkDrawIter iter(this);
610
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000611#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000612 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700613 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000614 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000616
reedc83a2972015-07-16 07:40:45 -0700617#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
618 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700619 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700620 while (looper.next(type)) { \
621 SkDrawIter iter(this);
622
reed@google.com4e2b3d32011-04-07 14:18:59 +0000623#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624
625////////////////////////////////////////////////////////////////////////////
626
msarettfbfa2582016-08-12 08:29:08 -0700627static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
628 if (bounds.isEmpty()) {
629 return SkRect::MakeEmpty();
630 }
631
632 // Expand bounds out by 1 in case we are anti-aliasing. We store the
633 // bounds as floats to enable a faster quick reject implementation.
634 SkRect dst;
635 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
636 return dst;
637}
638
mtkleinfeaadee2015-04-08 11:25:48 -0700639void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
640 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700641 fClipStack->reset();
642 fMCRec->reset(bounds);
643
644 // We're peering through a lot of structs here. Only at this scope do we
645 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
646 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700647 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700648 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700649}
650
reedd9544982014-09-09 18:46:22 -0700651SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800652 if (device && device->forceConservativeRasterClip()) {
653 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
654 }
655 // Since init() is only called once by our constructors, it is safe to perform this
656 // const-cast.
657 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
658
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000659 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700660 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800661 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700662 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700663#ifdef SK_EXPERIMENTAL_SHADOWING
664 fLights = nullptr;
665#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666
halcanary385fe4d2015-08-26 13:07:48 -0700667 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700668
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700670 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500671 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700672 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000673
reeda499f902015-05-01 09:34:31 -0700674 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
675 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700676 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700677 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700678
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680
halcanary96fcdcc2015-08-27 07:41:13 -0700681 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000682
reedf92c8662014-08-18 08:02:43 -0700683 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700684 // The root device and the canvas should always have the same pixel geometry
685 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700686 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800687 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700688 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700689 }
msarettfbfa2582016-08-12 08:29:08 -0700690
reedf92c8662014-08-18 08:02:43 -0700691 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692}
693
reed@google.comcde92112011-07-06 20:00:52 +0000694SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000695 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700696 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800697 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000698{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000699 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000700
halcanary96fcdcc2015-08-27 07:41:13 -0700701 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000702}
703
reedd9544982014-09-09 18:46:22 -0700704static SkBitmap make_nopixels(int width, int height) {
705 SkBitmap bitmap;
706 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
707 return bitmap;
708}
709
710class SkNoPixelsBitmapDevice : public SkBitmapDevice {
711public:
robertphillipsfcf78292015-06-19 11:49:52 -0700712 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
713 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800714 {
715 this->setOrigin(bounds.x(), bounds.y());
716 }
reedd9544982014-09-09 18:46:22 -0700717
718private:
piotaixrb5fae932014-09-24 13:03:30 -0700719
reedd9544982014-09-09 18:46:22 -0700720 typedef SkBitmapDevice INHERITED;
721};
722
reed96a857e2015-01-25 10:33:58 -0800723SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000724 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800725 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800726 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000727{
728 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700729
halcanary385fe4d2015-08-26 13:07:48 -0700730 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
731 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700732}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000733
reed78e27682014-11-19 08:04:34 -0800734SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700735 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700736 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800737 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700738{
739 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700740
halcanary385fe4d2015-08-26 13:07:48 -0700741 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700742}
743
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000744SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000745 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700746 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800747 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000748{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700750
reedd9544982014-09-09 18:46:22 -0700751 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752}
753
robertphillipsfcf78292015-06-19 11:49:52 -0700754SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
755 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700756 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800757 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700758{
759 inc_canvas();
760
761 this->init(device, flags);
762}
763
reed4a8126e2014-09-22 07:29:03 -0700764SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700765 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700766 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800767 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700768{
769 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700770
Hal Canary704cd322016-11-07 14:13:52 -0500771 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
772 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700773}
reed29c857d2014-09-21 10:25:07 -0700774
reed4a8126e2014-09-22 07:29:03 -0700775SkCanvas::SkCanvas(const SkBitmap& bitmap)
776 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
777 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800778 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700779{
780 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700781
Hal Canary704cd322016-11-07 14:13:52 -0500782 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
783 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000784}
785
786SkCanvas::~SkCanvas() {
787 // free up the contents of our deque
788 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000789
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790 this->internalRestore(); // restore the last, since we're going away
791
halcanary385fe4d2015-08-26 13:07:48 -0700792 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000793
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794 dec_canvas();
795}
796
fmalita53d9f1c2016-01-25 06:23:54 -0800797#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000798SkDrawFilter* SkCanvas::getDrawFilter() const {
799 return fMCRec->fFilter;
800}
801
802SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700803 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
805 return filter;
806}
fmalita77650002016-01-21 18:47:11 -0800807#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000809SkMetaData& SkCanvas::getMetaData() {
810 // metadata users are rare, so we lazily allocate it. If that changes we
811 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700812 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000813 fMetaData = new SkMetaData;
814 }
815 return *fMetaData;
816}
817
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818///////////////////////////////////////////////////////////////////////////////
819
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000820void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700821 this->onFlush();
822}
823
824void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000825 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000826 if (device) {
827 device->flush();
828 }
829}
830
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000831SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000832 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000833 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
834}
835
senorblancoafc7cce2016-02-02 18:44:15 -0800836SkIRect SkCanvas::getTopLayerBounds() const {
837 SkBaseDevice* d = this->getTopDevice();
838 if (!d) {
839 return SkIRect::MakeEmpty();
840 }
841 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
842}
843
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000844SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000846 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000847 SkASSERT(rec && rec->fLayer);
848 return rec->fLayer->fDevice;
849}
850
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000851SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000852 if (updateMatrixClip) {
853 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
854 }
reed@google.com9266fed2011-03-30 00:18:03 +0000855 return fMCRec->fTopLayer->fDevice;
856}
857
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000858bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700859 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000860 return false;
861 }
862
863 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700864 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700865 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000866 return false;
867 }
868 weAllocated = true;
869 }
870
reedcf01e312015-05-23 19:14:51 -0700871 SkAutoPixmapUnlock unlocker;
872 if (bitmap->requestLock(&unlocker)) {
873 const SkPixmap& pm = unlocker.pixmap();
874 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
875 return true;
876 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000877 }
878
879 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500880 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000881 }
882 return false;
883}
reed@google.com51df9e32010-12-23 19:29:18 +0000884
bsalomon@google.comc6980972011-11-02 19:57:21 +0000885bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000886 SkIRect r = srcRect;
887 const SkISize size = this->getBaseLayerSize();
888 if (!r.intersect(0, 0, size.width(), size.height())) {
889 bitmap->reset();
890 return false;
891 }
892
reed84825042014-09-02 12:50:45 -0700893 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000894 // bitmap will already be reset.
895 return false;
896 }
897 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
898 bitmap->reset();
899 return false;
900 }
901 return true;
902}
903
reed96472de2014-12-10 09:53:42 -0800904bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000905 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000906 if (!device) {
907 return false;
908 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000909 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800910
reed96472de2014-12-10 09:53:42 -0800911 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
912 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000913 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000914 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000915
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000916 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800917 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000918}
919
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000920bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700921 SkAutoPixmapUnlock unlocker;
922 if (bitmap.requestLock(&unlocker)) {
923 const SkPixmap& pm = unlocker.pixmap();
924 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000925 }
926 return false;
927}
928
929bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
930 int x, int y) {
931 switch (origInfo.colorType()) {
932 case kUnknown_SkColorType:
933 case kIndex_8_SkColorType:
934 return false;
935 default:
936 break;
937 }
halcanary96fcdcc2015-08-27 07:41:13 -0700938 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000939 return false;
940 }
941
942 const SkISize size = this->getBaseLayerSize();
943 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
944 if (!target.intersect(0, 0, size.width(), size.height())) {
945 return false;
946 }
947
948 SkBaseDevice* device = this->getDevice();
949 if (!device) {
950 return false;
951 }
952
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000953 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700954 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000955
956 // if x or y are negative, then we have to adjust pixels
957 if (x > 0) {
958 x = 0;
959 }
960 if (y > 0) {
961 y = 0;
962 }
963 // here x,y are either 0 or negative
964 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
965
reed4af35f32014-06-27 17:47:49 -0700966 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700967 const bool completeOverwrite = info.dimensions() == size;
968 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700969
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000970 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000971 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000972}
reed@google.com51df9e32010-12-23 19:29:18 +0000973
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974//////////////////////////////////////////////////////////////////////////////
975
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976void SkCanvas::updateDeviceCMCache() {
977 if (fDeviceCMDirty) {
978 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700979 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000981
halcanary96fcdcc2015-08-27 07:41:13 -0700982 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700983 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000985 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986 do {
reedde6c5312016-09-02 12:10:07 -0700987 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700988 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989 }
990 fDeviceCMDirty = false;
991 }
992}
993
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994///////////////////////////////////////////////////////////////////////////////
995
reed2ff1fce2014-12-11 07:07:37 -0800996void SkCanvas::checkForDeferredSave() {
997 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800998 this->doSave();
999 }
1000}
1001
reedf0090cb2014-11-26 08:55:51 -08001002int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -08001003#ifdef SK_DEBUG
1004 int count = 0;
1005 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1006 for (;;) {
1007 const MCRec* rec = (const MCRec*)iter.next();
1008 if (!rec) {
1009 break;
1010 }
1011 count += 1 + rec->fDeferredSaveCount;
1012 }
1013 SkASSERT(count == fSaveCount);
1014#endif
1015 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001016}
1017
1018int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001019 fSaveCount += 1;
1020 fMCRec->fDeferredSaveCount += 1;
1021 return this->getSaveCount() - 1; // return our prev value
1022}
1023
1024void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001025 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001026
1027 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1028 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001029 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001030}
1031
1032void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001033 if (fMCRec->fDeferredSaveCount > 0) {
1034 SkASSERT(fSaveCount > 1);
1035 fSaveCount -= 1;
1036 fMCRec->fDeferredSaveCount -= 1;
1037 } else {
1038 // check for underflow
1039 if (fMCStack.count() > 1) {
1040 this->willRestore();
1041 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001042 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001043 this->internalRestore();
1044 this->didRestore();
1045 }
reedf0090cb2014-11-26 08:55:51 -08001046 }
1047}
1048
1049void SkCanvas::restoreToCount(int count) {
1050 // sanity check
1051 if (count < 1) {
1052 count = 1;
1053 }
mtkleinf0f14112014-12-12 08:46:25 -08001054
reedf0090cb2014-11-26 08:55:51 -08001055 int n = this->getSaveCount() - count;
1056 for (int i = 0; i < n; ++i) {
1057 this->restore();
1058 }
1059}
1060
reed2ff1fce2014-12-11 07:07:37 -08001061void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001063 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001065
reed687fa1c2015-04-07 08:00:56 -07001066 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067}
1068
reed4960eee2015-12-18 07:09:18 -08001069bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001070 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001071}
1072
reed4960eee2015-12-18 07:09:18 -08001073bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001074 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001075 SkIRect clipBounds;
1076 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001077 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001078 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001079
reed96e657d2015-03-10 17:30:07 -07001080 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1081
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001082 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001083 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001084 if (bounds && !imageFilter->canComputeFastBounds()) {
1085 bounds = nullptr;
1086 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001087 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001088 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001089 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001091
reed96e657d2015-03-10 17:30:07 -07001092 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093 r.roundOut(&ir);
1094 // early exit if the layer's bounds are clipped out
1095 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001096 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001097 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001098 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001099 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001100 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101 }
1102 } else { // no user bounds, so just use the clip
1103 ir = clipBounds;
1104 }
reed180aec42015-03-11 10:39:04 -07001105 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106
reed4960eee2015-12-18 07:09:18 -08001107 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001108 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001109 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001110 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001111 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001112 }
1113
1114 if (intersection) {
1115 *intersection = ir;
1116 }
1117 return true;
1118}
1119
reed4960eee2015-12-18 07:09:18 -08001120
reed4960eee2015-12-18 07:09:18 -08001121int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1122 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001123}
1124
reed70ee31b2015-12-10 13:44:45 -08001125int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001126 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1127}
1128
1129int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1130 SaveLayerRec rec(origRec);
1131 if (gIgnoreSaveLayerBounds) {
1132 rec.fBounds = nullptr;
1133 }
1134 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1135 fSaveCount += 1;
1136 this->internalSaveLayer(rec, strategy);
1137 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001138}
1139
reeda2217ef2016-07-20 06:04:34 -07001140void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1141 SkBaseDevice* dst, const SkMatrix& ctm,
1142 const SkClipStack* clipStack) {
1143 SkDraw draw;
1144 SkRasterClip rc;
1145 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1146 if (!dst->accessPixels(&draw.fDst)) {
1147 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001148 }
reeda2217ef2016-07-20 06:04:34 -07001149 draw.fMatrix = &SkMatrix::I();
1150 draw.fRC = &rc;
1151 draw.fClipStack = clipStack;
1152 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001153
1154 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001155 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001156
1157 int x = src->getOrigin().x() - dst->getOrigin().x();
1158 int y = src->getOrigin().y() - dst->getOrigin().y();
1159 auto special = src->snapSpecial();
1160 if (special) {
1161 dst->drawSpecial(draw, special.get(), x, y, p);
1162 }
robertphillips7354a4b2015-12-16 05:08:27 -08001163}
reed70ee31b2015-12-10 13:44:45 -08001164
reed129ed1c2016-02-22 06:42:31 -08001165static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1166 const SkPaint* paint) {
1167 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1168 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001169 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001170 const bool hasImageFilter = paint && paint->getImageFilter();
1171
1172 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1173 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1174 // force to L32
1175 return SkImageInfo::MakeN32(w, h, alphaType);
1176 } else {
1177 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001178 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001179 }
1180}
1181
reed4960eee2015-12-18 07:09:18 -08001182void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1183 const SkRect* bounds = rec.fBounds;
1184 const SkPaint* paint = rec.fPaint;
1185 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1186
reed8c30a812016-04-20 16:36:51 -07001187 SkLazyPaint lazyP;
1188 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1189 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001190 SkMatrix remainder;
1191 SkSize scale;
1192 /*
1193 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1194 * but they do handle scaling. To accommodate this, we do the following:
1195 *
1196 * 1. Stash off the current CTM
1197 * 2. Decompose the CTM into SCALE and REMAINDER
1198 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1199 * contains the REMAINDER
1200 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1201 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1202 * of the original imagefilter, and draw that (via drawSprite)
1203 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1204 *
1205 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1206 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1207 */
reed96a04f32016-04-25 09:25:15 -07001208 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001209 stashedMatrix.decomposeScale(&scale, &remainder))
1210 {
1211 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1212 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1213 SkPaint* p = lazyP.set(*paint);
1214 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1215 SkFilterQuality::kLow_SkFilterQuality,
1216 sk_ref_sp(imageFilter)));
1217 imageFilter = p->getImageFilter();
1218 paint = p;
1219 }
reed8c30a812016-04-20 16:36:51 -07001220
junov@chromium.orga907ac32012-02-24 21:54:07 +00001221 // do this before we create the layer. We don't call the public save() since
1222 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001223 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001224
1225 fDeviceCMDirty = true;
1226
1227 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001228 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001229 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230 }
1231
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001232 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1233 // the clipRectBounds() call above?
1234 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001235 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001236 }
1237
reed4960eee2015-12-18 07:09:18 -08001238 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001239 SkPixelGeometry geo = fProps.pixelGeometry();
1240 if (paint) {
reed76033be2015-03-14 10:54:31 -07001241 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001242 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001243 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001244 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001245 }
1246 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247
robertphillips5139e502016-07-19 05:10:40 -07001248 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001249 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001250 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001251 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001252 }
reedb2db8982014-11-13 12:41:02 -08001253
robertphillips5139e502016-07-19 05:10:40 -07001254 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001255 paint);
1256
Hal Canary704cd322016-11-07 14:13:52 -05001257 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001258 {
reed70ee31b2015-12-10 13:44:45 -08001259 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001260 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001261 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001262 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
reedcd4051e2016-07-15 09:41:26 -07001263 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001264 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1265 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001266 return;
reed61f501f2015-04-29 08:34:00 -07001267 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001268 }
robertphillips5139e502016-07-19 05:10:40 -07001269 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001270
Hal Canary704cd322016-11-07 14:13:52 -05001271 DeviceCM* layer =
1272 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273
1274 layer->fNext = fMCRec->fTopLayer;
1275 fMCRec->fLayer = layer;
1276 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001277
1278 if (rec.fBackdrop) {
Hal Canary704cd322016-11-07 14:13:52 -05001279 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
reeda2217ef2016-07-20 06:04:34 -07001280 fMCRec->fMatrix, this->getClipStack());
1281 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282}
1283
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001284int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001285 if (0xFF == alpha) {
1286 return this->saveLayer(bounds, nullptr);
1287 } else {
1288 SkPaint tmpPaint;
1289 tmpPaint.setAlpha(alpha);
1290 return this->saveLayer(bounds, &tmpPaint);
1291 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001292}
1293
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294void SkCanvas::internalRestore() {
1295 SkASSERT(fMCStack.count() != 0);
1296
1297 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298
reed687fa1c2015-04-07 08:00:56 -07001299 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001300
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001301 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 DeviceCM* layer = fMCRec->fLayer; // may be null
1303 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001304 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305
1306 // now do the normal restore()
1307 fMCRec->~MCRec(); // balanced in save()
1308 fMCStack.pop_back();
1309 fMCRec = (MCRec*)fMCStack.back();
1310
1311 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1312 since if we're being recorded, we don't want to record this (the
1313 recorder will have already recorded the restore).
1314 */
bsalomon49f085d2014-09-05 13:34:00 -07001315 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001316 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001317 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001318 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001319 // restore what we smashed in internalSaveLayer
1320 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001321 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001323 delete layer;
reedb679ca82015-04-07 04:40:48 -07001324 } else {
1325 // we're at the root
reeda499f902015-05-01 09:34:31 -07001326 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001327 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001328 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001329 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001330 }
msarettfbfa2582016-08-12 08:29:08 -07001331
1332 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001333 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001334 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1335 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001336}
1337
reede8f30622016-03-23 18:59:25 -07001338sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001339 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001340 props = &fProps;
1341 }
1342 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001343}
1344
reede8f30622016-03-23 18:59:25 -07001345sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001346 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001347 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001348}
1349
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001350SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001351 return this->onImageInfo();
1352}
1353
1354SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001355 SkBaseDevice* dev = this->getDevice();
1356 if (dev) {
1357 return dev->imageInfo();
1358 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001359 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001360 }
1361}
1362
brianosman898235c2016-04-06 07:38:23 -07001363bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001364 return this->onGetProps(props);
1365}
1366
1367bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001368 SkBaseDevice* dev = this->getDevice();
1369 if (dev) {
1370 if (props) {
1371 *props = fProps;
1372 }
1373 return true;
1374 } else {
1375 return false;
1376 }
1377}
1378
reed6ceeebd2016-03-09 14:26:26 -08001379bool SkCanvas::peekPixels(SkPixmap* pmap) {
1380 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001381}
1382
reed884e97c2015-05-26 11:31:54 -07001383bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001384 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001385 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001386}
1387
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001388void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001389 SkPixmap pmap;
1390 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001391 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001392 }
1393 if (info) {
1394 *info = pmap.info();
1395 }
1396 if (rowBytes) {
1397 *rowBytes = pmap.rowBytes();
1398 }
1399 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001400 *origin = this->getTopDevice(false)->getOrigin();
1401 }
reed884e97c2015-05-26 11:31:54 -07001402 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001403}
1404
reed884e97c2015-05-26 11:31:54 -07001405bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001406 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001407 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001408}
1409
reed@android.com8a1c16f2008-12-17 15:59:43 +00001410/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001411
reed7503d602016-07-15 14:23:29 -07001412void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001414 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415 paint = &tmp;
1416 }
reed@google.com4b226022011-01-11 18:32:13 +00001417
reed@google.com8926b162012-03-23 15:36:36 +00001418 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001419
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001421 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001422 paint = &looper.paint();
1423 SkImageFilter* filter = paint->getImageFilter();
1424 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001425 if (filter) {
1426 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1427 if (specialImage) {
1428 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1429 }
reed@google.com76dd2772012-01-05 21:15:07 +00001430 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001431 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001432 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433 }
reeda2217ef2016-07-20 06:04:34 -07001434
reed@google.com4e2b3d32011-04-07 14:18:59 +00001435 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436}
1437
reed32704672015-12-16 08:27:10 -08001438/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001439
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001440void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001441 if (dx || dy) {
1442 this->checkForDeferredSave();
1443 fDeviceCMDirty = true;
1444 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001445
reedfe69b502016-09-12 06:31:48 -07001446 // Translate shouldn't affect the is-scale-translateness of the matrix.
1447 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001448
reedfe69b502016-09-12 06:31:48 -07001449 this->didTranslate(dx,dy);
1450 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001451}
1452
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001453void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001454 SkMatrix m;
1455 m.setScale(sx, sy);
1456 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001457}
1458
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001459void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001460 SkMatrix m;
1461 m.setRotate(degrees);
1462 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001463}
1464
bungeman7438bfc2016-07-12 15:01:19 -07001465void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1466 SkMatrix m;
1467 m.setRotate(degrees, px, py);
1468 this->concat(m);
1469}
1470
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001471void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001472 SkMatrix m;
1473 m.setSkew(sx, sy);
1474 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001475}
1476
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001477void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001478 if (matrix.isIdentity()) {
1479 return;
1480 }
1481
reed2ff1fce2014-12-11 07:07:37 -08001482 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001483 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001484 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001485 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001486 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001487}
1488
reed8c30a812016-04-20 16:36:51 -07001489void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001490 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001491 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001492 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001493}
1494
1495void SkCanvas::setMatrix(const SkMatrix& matrix) {
1496 this->checkForDeferredSave();
1497 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001498 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001499}
1500
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001502 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503}
1504
vjiaoblack95302da2016-07-21 10:25:54 -07001505#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001506void SkCanvas::translateZ(SkScalar z) {
1507 this->checkForDeferredSave();
1508 this->fMCRec->fCurDrawDepth += z;
1509 this->didTranslateZ(z);
1510}
1511
1512SkScalar SkCanvas::getZ() const {
1513 return this->fMCRec->fCurDrawDepth;
1514}
1515
vjiaoblack95302da2016-07-21 10:25:54 -07001516void SkCanvas::setLights(sk_sp<SkLights> lights) {
1517 this->fLights = lights;
1518}
1519
1520sk_sp<SkLights> SkCanvas::getLights() const {
1521 return this->fLights;
1522}
1523#endif
1524
reed@android.com8a1c16f2008-12-17 15:59:43 +00001525//////////////////////////////////////////////////////////////////////////////
1526
Mike Reedc1f77742016-12-09 09:00:50 -05001527void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001528 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001529 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1530 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001531}
1532
Mike Reedc1f77742016-12-09 09:00:50 -05001533void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001534 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reedc64eff52015-11-21 12:39:45 -08001535 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001536 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1537 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1538 isAA);
reedc64eff52015-11-21 12:39:45 -08001539 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001540 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001541}
1542
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001543void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1544 fClipRestrictionRect = rect;
1545 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
1546 if (!fClipRestrictionRect.isEmpty()) {
1547 this->checkForDeferredSave();
1548 AutoValidateClip avc(this);
1549 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1550 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1551 fDeviceCMDirty = true;
1552 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1553 }
1554}
1555
Mike Reedc1f77742016-12-09 09:00:50 -05001556void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001557 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001558 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001559 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001560 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1561 } else {
1562 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001563 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001564}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001565
Mike Reedc1f77742016-12-09 09:00:50 -05001566void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001567 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001568
Brian Salomona3b45d42016-10-03 11:36:16 -04001569 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001570
Brian Salomona3b45d42016-10-03 11:36:16 -04001571 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1572 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1573 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1574 isAA);
1575 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1576 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001577}
1578
Mike Reedc1f77742016-12-09 09:00:50 -05001579void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001580 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001581 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001582
1583 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1584 SkRect r;
1585 if (path.isRect(&r)) {
1586 this->onClipRect(r, op, edgeStyle);
1587 return;
1588 }
1589 SkRRect rrect;
1590 if (path.isOval(&r)) {
1591 rrect.setOval(r);
1592 this->onClipRRect(rrect, op, edgeStyle);
1593 return;
1594 }
1595 if (path.isRRect(&rrect)) {
1596 this->onClipRRect(rrect, op, edgeStyle);
1597 return;
1598 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001599 }
robertphillips39f05382015-11-24 09:30:12 -08001600
1601 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001602}
1603
Mike Reedc1f77742016-12-09 09:00:50 -05001604void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001605 AutoValidateClip avc(this);
1606
reed@android.com8a1c16f2008-12-17 15:59:43 +00001607 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001608 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001609
Brian Salomona3b45d42016-10-03 11:36:16 -04001610 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611
Brian Salomona3b45d42016-10-03 11:36:16 -04001612 const SkPath* rasterClipPath = &path;
1613 const SkMatrix* matrix = &fMCRec->fMatrix;
1614 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001615 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001616 isAA = getClipStack()->asPath(&tempPath);
1617 rasterClipPath = &tempPath;
1618 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001619 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001620 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001621 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1622 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001623 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001624}
1625
Mike Reedc1f77742016-12-09 09:00:50 -05001626void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001627 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001628 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001629}
1630
Mike Reedc1f77742016-12-09 09:00:50 -05001631void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001632 AutoValidateClip avc(this);
1633
reed@android.com8a1c16f2008-12-17 15:59:43 +00001634 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001635
reed@google.com5c3d1472011-02-22 19:12:23 +00001636 // todo: signal fClipStack that we have a region, and therefore (I guess)
1637 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001638 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001639
reed73603f32016-09-20 08:42:38 -07001640 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001641 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001642}
1643
reed@google.com819c9212011-02-23 18:56:55 +00001644#ifdef SK_DEBUG
1645void SkCanvas::validateClip() const {
1646 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001647 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001648 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001649 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001650 return;
1651 }
1652
reed@google.com819c9212011-02-23 18:56:55 +00001653 SkIRect ir;
1654 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001655 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001656
reed687fa1c2015-04-07 08:00:56 -07001657 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001658 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001659 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001660 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001661 case SkClipStack::Element::kRect_Type:
1662 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001663 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001664 break;
1665 case SkClipStack::Element::kEmpty_Type:
1666 tmpClip.setEmpty();
1667 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001668 default: {
1669 SkPath path;
1670 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001671 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1672 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001673 break;
1674 }
reed@google.com819c9212011-02-23 18:56:55 +00001675 }
1676 }
reed@google.com819c9212011-02-23 18:56:55 +00001677}
1678#endif
1679
reed@google.com90c07ea2012-04-13 13:50:27 +00001680void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001681 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001682 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001683
halcanary96fcdcc2015-08-27 07:41:13 -07001684 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001685 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001686 }
1687}
1688
reed@google.com5c3d1472011-02-22 19:12:23 +00001689///////////////////////////////////////////////////////////////////////////////
1690
reed@google.com754de5f2014-02-24 19:38:20 +00001691bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001692 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001693}
1694
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001695bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001696 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001697}
1698
msarettfbfa2582016-08-12 08:29:08 -07001699static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1700#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1701 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1702 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1703 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1704 return 0xF != _mm_movemask_ps(mask);
1705#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1706 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1707 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1708 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1709 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1710#else
1711 SkRect devRectAsRect;
1712 SkRect devClipAsRect;
1713 devRect.store(&devRectAsRect.fLeft);
1714 devClip.store(&devClipAsRect.fLeft);
1715 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1716#endif
1717}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001718
msarettfbfa2582016-08-12 08:29:08 -07001719// It's important for this function to not be inlined. Otherwise the compiler will share code
1720// between the fast path and the slow path, resulting in two slow paths.
1721static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1722 const SkMatrix& matrix) {
1723 SkRect deviceRect;
1724 matrix.mapRect(&deviceRect, src);
1725 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1726}
1727
1728bool SkCanvas::quickReject(const SkRect& src) const {
1729#ifdef SK_DEBUG
1730 // Verify that fDeviceClipBounds are set properly.
1731 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001732 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001733 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001734 } else {
msarettfbfa2582016-08-12 08:29:08 -07001735 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001736 }
msarettfbfa2582016-08-12 08:29:08 -07001737
msarett9637ea92016-08-18 14:03:30 -07001738 // Verify that fIsScaleTranslate is set properly.
1739 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001740#endif
1741
msarett9637ea92016-08-18 14:03:30 -07001742 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001743 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1744 }
1745
1746 // We inline the implementation of mapScaleTranslate() for the fast path.
1747 float sx = fMCRec->fMatrix.getScaleX();
1748 float sy = fMCRec->fMatrix.getScaleY();
1749 float tx = fMCRec->fMatrix.getTranslateX();
1750 float ty = fMCRec->fMatrix.getTranslateY();
1751 Sk4f scale(sx, sy, sx, sy);
1752 Sk4f trans(tx, ty, tx, ty);
1753
1754 // Apply matrix.
1755 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1756
1757 // Make sure left < right, top < bottom.
1758 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1759 Sk4f min = Sk4f::Min(ltrb, rblt);
1760 Sk4f max = Sk4f::Max(ltrb, rblt);
1761 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1762 // ARM this sequence generates the fastest (a single instruction).
1763 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1764
1765 // Check if the device rect is NaN or outside the clip.
1766 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001767}
1768
reed@google.com3b3e8952012-08-16 20:53:31 +00001769bool SkCanvas::quickReject(const SkPath& path) const {
1770 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001771}
1772
reed@google.com3b3e8952012-08-16 20:53:31 +00001773bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001774 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001775 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001776 return false;
1777 }
1778
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001779 SkMatrix inverse;
1780 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001781 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001782 if (bounds) {
1783 bounds->setEmpty();
1784 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001785 return false;
1786 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001787
bsalomon49f085d2014-09-05 13:34:00 -07001788 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001789 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001790 // adjust it outwards in case we are antialiasing
1791 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001792
reed@google.com8f4d2302013-12-17 16:44:46 +00001793 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1794 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001795 inverse.mapRect(bounds, r);
1796 }
1797 return true;
1798}
1799
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001800bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001801 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001802 if (clip.isEmpty()) {
1803 if (bounds) {
1804 bounds->setEmpty();
1805 }
1806 return false;
1807 }
1808
bsalomon49f085d2014-09-05 13:34:00 -07001809 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001810 *bounds = clip.getBounds();
1811 }
1812 return true;
1813}
1814
reed@android.com8a1c16f2008-12-17 15:59:43 +00001815const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001816 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001817}
1818
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001819const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001820 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001821}
1822
Brian Osman11052242016-10-27 14:47:55 -04001823GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001824 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001825 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001826}
1827
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001828GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001829 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001830 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001831}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001832
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001833void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1834 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001835 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001836 if (outer.isEmpty()) {
1837 return;
1838 }
1839 if (inner.isEmpty()) {
1840 this->drawRRect(outer, paint);
1841 return;
1842 }
1843
1844 // We don't have this method (yet), but technically this is what we should
1845 // be able to assert...
1846 // SkASSERT(outer.contains(inner));
1847 //
1848 // For now at least check for containment of bounds
1849 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1850
1851 this->onDrawDRRect(outer, inner, paint);
1852}
1853
reed41af9662015-01-05 07:49:08 -08001854// These need to stop being virtual -- clients need to override the onDraw... versions
1855
1856void SkCanvas::drawPaint(const SkPaint& paint) {
1857 this->onDrawPaint(paint);
1858}
1859
1860void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1861 this->onDrawRect(r, paint);
1862}
1863
msarettdca352e2016-08-26 06:37:45 -07001864void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1865 if (region.isEmpty()) {
1866 return;
1867 }
1868
1869 if (region.isRect()) {
1870 return this->drawIRect(region.getBounds(), paint);
1871 }
1872
1873 this->onDrawRegion(region, paint);
1874}
1875
reed41af9662015-01-05 07:49:08 -08001876void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1877 this->onDrawOval(r, paint);
1878}
1879
1880void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1881 this->onDrawRRect(rrect, paint);
1882}
1883
1884void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1885 this->onDrawPoints(mode, count, pts, paint);
1886}
1887
1888void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001889 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001890 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reedfaba3712016-11-03 14:45:31 -04001891 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, bmode,
reed41af9662015-01-05 07:49:08 -08001892 indices, indexCount, paint);
1893}
1894
1895void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1896 this->onDrawPath(path, paint);
1897}
1898
reeda85d4d02015-05-06 12:56:48 -07001899void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001900 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001901 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001902}
1903
reede47829b2015-08-06 10:02:53 -07001904void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1905 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001906 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001907 if (dst.isEmpty() || src.isEmpty()) {
1908 return;
1909 }
1910 this->onDrawImageRect(image, &src, dst, paint, constraint);
1911}
reed41af9662015-01-05 07:49:08 -08001912
reed84984ef2015-07-17 07:09:43 -07001913void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1914 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001915 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001916 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001917}
1918
reede47829b2015-08-06 10:02:53 -07001919void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1920 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001921 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001922 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1923 constraint);
1924}
reede47829b2015-08-06 10:02:53 -07001925
reed4c21dc52015-06-25 12:32:03 -07001926void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1927 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001928 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001929 if (dst.isEmpty()) {
1930 return;
1931 }
msarett552bca92016-08-03 06:53:26 -07001932 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1933 this->onDrawImageNine(image, center, dst, paint);
1934 } else {
reede47829b2015-08-06 10:02:53 -07001935 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001936 }
reed4c21dc52015-06-25 12:32:03 -07001937}
1938
msarett16882062016-08-16 09:31:08 -07001939void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1940 const SkPaint* paint) {
1941 RETURN_ON_NULL(image);
1942 if (dst.isEmpty()) {
1943 return;
1944 }
msarett71df2d72016-09-30 12:41:42 -07001945
1946 SkIRect bounds;
1947 Lattice latticePlusBounds = lattice;
1948 if (!latticePlusBounds.fBounds) {
1949 bounds = SkIRect::MakeWH(image->width(), image->height());
1950 latticePlusBounds.fBounds = &bounds;
1951 }
1952
1953 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1954 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001955 } else {
1956 this->drawImageRect(image, dst, paint);
1957 }
1958}
1959
reed41af9662015-01-05 07:49:08 -08001960void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001961 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001962 return;
1963 }
reed41af9662015-01-05 07:49:08 -08001964 this->onDrawBitmap(bitmap, dx, dy, paint);
1965}
1966
reede47829b2015-08-06 10:02:53 -07001967void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001968 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001969 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001970 return;
1971 }
reede47829b2015-08-06 10:02:53 -07001972 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001973}
1974
reed84984ef2015-07-17 07:09:43 -07001975void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1976 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001977 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001978}
1979
reede47829b2015-08-06 10:02:53 -07001980void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1981 SrcRectConstraint constraint) {
1982 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1983 constraint);
1984}
reede47829b2015-08-06 10:02:53 -07001985
reed41af9662015-01-05 07:49:08 -08001986void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1987 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001988 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001989 return;
1990 }
msarett552bca92016-08-03 06:53:26 -07001991 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1992 this->onDrawBitmapNine(bitmap, center, dst, paint);
1993 } else {
reeda5517e22015-07-14 10:54:12 -07001994 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001995 }
reed41af9662015-01-05 07:49:08 -08001996}
1997
msarettc573a402016-08-02 08:05:56 -07001998void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1999 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002000 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002001 return;
2002 }
msarett71df2d72016-09-30 12:41:42 -07002003
2004 SkIRect bounds;
2005 Lattice latticePlusBounds = lattice;
2006 if (!latticePlusBounds.fBounds) {
2007 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2008 latticePlusBounds.fBounds = &bounds;
2009 }
2010
2011 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2012 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002013 } else {
msarett16882062016-08-16 09:31:08 -07002014 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002015 }
msarettc573a402016-08-02 08:05:56 -07002016}
2017
reed71c3c762015-06-24 10:29:17 -07002018void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002019 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002020 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002021 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002022 if (count <= 0) {
2023 return;
2024 }
2025 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002026 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002027 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002028}
2029
reedf70b5312016-03-04 16:36:20 -08002030void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2031 if (key) {
2032 this->onDrawAnnotation(rect, key, value);
2033 }
2034}
2035
reede47829b2015-08-06 10:02:53 -07002036void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2037 const SkPaint* paint, SrcRectConstraint constraint) {
2038 if (src) {
2039 this->drawImageRect(image, *src, dst, paint, constraint);
2040 } else {
2041 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2042 dst, paint, constraint);
2043 }
2044}
2045void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2046 const SkPaint* paint, SrcRectConstraint constraint) {
2047 if (src) {
2048 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2049 } else {
2050 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2051 dst, paint, constraint);
2052 }
2053}
2054
tomhudsoncb3bd182016-05-18 07:24:16 -07002055void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2056 SkIRect layer_bounds = this->getTopLayerBounds();
2057 if (matrix) {
2058 *matrix = this->getTotalMatrix();
2059 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2060 }
2061 if (clip_bounds) {
2062 this->getClipDeviceBounds(clip_bounds);
2063 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2064 }
2065}
2066
reed@android.com8a1c16f2008-12-17 15:59:43 +00002067//////////////////////////////////////////////////////////////////////////////
2068// These are the virtual drawing methods
2069//////////////////////////////////////////////////////////////////////////////
2070
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002071void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002072 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002073 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2074 }
2075}
2076
reed41af9662015-01-05 07:49:08 -08002077void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002078 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002079 this->internalDrawPaint(paint);
2080}
2081
2082void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002083 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002084
2085 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002086 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002087 }
2088
reed@google.com4e2b3d32011-04-07 14:18:59 +00002089 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002090}
2091
reed41af9662015-01-05 07:49:08 -08002092void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2093 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002094 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002095 if ((long)count <= 0) {
2096 return;
2097 }
2098
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002099 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002100 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002101 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002102 // special-case 2 points (common for drawing a single line)
2103 if (2 == count) {
2104 r.set(pts[0], pts[1]);
2105 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002106 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002107 }
senorblanco87e066e2015-10-28 11:23:36 -07002108 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2109 return;
2110 }
2111 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002112 }
reed@google.coma584aed2012-05-16 14:06:02 +00002113
halcanary96fcdcc2015-08-27 07:41:13 -07002114 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002115
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002116 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002117
reed@android.com8a1c16f2008-12-17 15:59:43 +00002118 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002119 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002120 }
reed@google.com4b226022011-01-11 18:32:13 +00002121
reed@google.com4e2b3d32011-04-07 14:18:59 +00002122 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002123}
2124
reed4a167172016-08-18 17:15:25 -07002125static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2126 return ((intptr_t)paint.getImageFilter() |
2127#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2128 (intptr_t)canvas->getDrawFilter() |
2129#endif
2130 (intptr_t)paint.getLooper() ) != 0;
2131}
2132
reed41af9662015-01-05 07:49:08 -08002133void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002134 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002135 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002136 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002137 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002138 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2139 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2140 SkRect tmp(r);
2141 tmp.sort();
2142
senorblanco87e066e2015-10-28 11:23:36 -07002143 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2144 return;
2145 }
2146 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002147 }
reed@google.com4b226022011-01-11 18:32:13 +00002148
reed4a167172016-08-18 17:15:25 -07002149 if (needs_autodrawlooper(this, paint)) {
2150 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151
reed4a167172016-08-18 17:15:25 -07002152 while (iter.next()) {
2153 iter.fDevice->drawRect(iter, r, looper.paint());
2154 }
2155
2156 LOOPER_END
2157 } else {
2158 this->predrawNotify(bounds, &paint, false);
2159 SkDrawIter iter(this);
2160 while (iter.next()) {
2161 iter.fDevice->drawRect(iter, r, paint);
2162 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002163 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002164}
2165
msarett44df6512016-08-25 13:54:30 -07002166void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2167 SkRect storage;
2168 SkRect regionRect = SkRect::Make(region.getBounds());
2169 const SkRect* bounds = nullptr;
2170 if (paint.canComputeFastBounds()) {
2171 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2172 return;
2173 }
2174 bounds = &regionRect;
2175 }
2176
2177 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2178
2179 while (iter.next()) {
2180 iter.fDevice->drawRegion(iter, region, looper.paint());
2181 }
2182
2183 LOOPER_END
2184}
2185
reed41af9662015-01-05 07:49:08 -08002186void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002187 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002188 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002189 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002190 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002191 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2192 return;
2193 }
2194 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002195 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002196
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002197 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002198
2199 while (iter.next()) {
2200 iter.fDevice->drawOval(iter, oval, looper.paint());
2201 }
2202
2203 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002204}
2205
bsalomonac3aa242016-08-19 11:25:19 -07002206void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2207 SkScalar sweepAngle, bool useCenter,
2208 const SkPaint& paint) {
2209 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2210 const SkRect* bounds = nullptr;
2211 if (paint.canComputeFastBounds()) {
2212 SkRect storage;
2213 // Note we're using the entire oval as the bounds.
2214 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2215 return;
2216 }
2217 bounds = &oval;
2218 }
2219
2220 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2221
2222 while (iter.next()) {
2223 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2224 }
2225
2226 LOOPER_END
2227}
2228
reed41af9662015-01-05 07:49:08 -08002229void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002230 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002231 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002232 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002233 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002234 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2235 return;
2236 }
2237 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002238 }
2239
2240 if (rrect.isRect()) {
2241 // call the non-virtual version
2242 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002243 return;
2244 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002245 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002246 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2247 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002248 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002249
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002250 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002251
2252 while (iter.next()) {
2253 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2254 }
2255
2256 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002257}
2258
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002259void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2260 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002261 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002262 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002263 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002264 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2265 return;
2266 }
2267 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002268 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002269
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002270 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002271
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002272 while (iter.next()) {
2273 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2274 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002275
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002276 LOOPER_END
2277}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002278
reed41af9662015-01-05 07:49:08 -08002279void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002280 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002281 if (!path.isFinite()) {
2282 return;
2283 }
2284
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002285 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002286 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002287 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002288 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002289 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2290 return;
2291 }
2292 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002293 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002294
2295 const SkRect& r = path.getBounds();
2296 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002297 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002298 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002299 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002300 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002301 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002303 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002304
2305 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002306 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 }
2308
reed@google.com4e2b3d32011-04-07 14:18:59 +00002309 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002310}
2311
reed262a71b2015-12-05 13:07:27 -08002312bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002313 if (!paint.getImageFilter()) {
2314 return false;
2315 }
2316
2317 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002318 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002319 return false;
2320 }
2321
2322 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2323 // Once we can filter and the filter will return a result larger than itself, we should be
2324 // able to remove this constraint.
2325 // skbug.com/4526
2326 //
2327 SkPoint pt;
2328 ctm.mapXY(x, y, &pt);
2329 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2330 return ir.contains(fMCRec->fRasterClip.getBounds());
2331}
2332
reeda85d4d02015-05-06 12:56:48 -07002333void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002334 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002335 SkRect bounds = SkRect::MakeXYWH(x, y,
2336 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002337 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002338 SkRect tmp = bounds;
2339 if (paint) {
2340 paint->computeFastBounds(tmp, &tmp);
2341 }
2342 if (this->quickReject(tmp)) {
2343 return;
2344 }
reeda85d4d02015-05-06 12:56:48 -07002345 }
halcanary9d524f22016-03-29 09:03:52 -07002346
reeda85d4d02015-05-06 12:56:48 -07002347 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002348 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002349 paint = lazy.init();
2350 }
reed262a71b2015-12-05 13:07:27 -08002351
reeda2217ef2016-07-20 06:04:34 -07002352 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002353 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2354 *paint);
2355 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002356 special = this->getDevice()->makeSpecial(image);
2357 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002358 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002359 }
2360 }
2361
reed262a71b2015-12-05 13:07:27 -08002362 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2363
reeda85d4d02015-05-06 12:56:48 -07002364 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002365 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002366 if (special) {
2367 SkPoint pt;
2368 iter.fMatrix->mapXY(x, y, &pt);
2369 iter.fDevice->drawSpecial(iter, special.get(),
2370 SkScalarRoundToInt(pt.fX),
2371 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002372 } else {
2373 iter.fDevice->drawImage(iter, image, x, y, pnt);
2374 }
reeda85d4d02015-05-06 12:56:48 -07002375 }
halcanary9d524f22016-03-29 09:03:52 -07002376
reeda85d4d02015-05-06 12:56:48 -07002377 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002378}
2379
reed41af9662015-01-05 07:49:08 -08002380void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002381 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002382 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002383 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002384 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002385 if (paint) {
2386 paint->computeFastBounds(dst, &storage);
2387 }
2388 if (this->quickReject(storage)) {
2389 return;
2390 }
reeda85d4d02015-05-06 12:56:48 -07002391 }
2392 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002393 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002394 paint = lazy.init();
2395 }
halcanary9d524f22016-03-29 09:03:52 -07002396
senorblancoc41e7e12015-12-07 12:51:30 -08002397 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002398 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002399
reeda85d4d02015-05-06 12:56:48 -07002400 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002401 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002402 }
halcanary9d524f22016-03-29 09:03:52 -07002403
reeda85d4d02015-05-06 12:56:48 -07002404 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002405}
2406
reed41af9662015-01-05 07:49:08 -08002407void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002408 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002409 SkDEBUGCODE(bitmap.validate();)
2410
reed33366972015-10-08 09:22:02 -07002411 if (bitmap.drawsNothing()) {
2412 return;
2413 }
2414
2415 SkLazyPaint lazy;
2416 if (nullptr == paint) {
2417 paint = lazy.init();
2418 }
2419
2420 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2421
2422 SkRect storage;
2423 const SkRect* bounds = nullptr;
2424 if (paint->canComputeFastBounds()) {
2425 bitmap.getBounds(&storage);
2426 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002427 SkRect tmp = storage;
2428 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2429 return;
2430 }
2431 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002432 }
reed@google.com4b226022011-01-11 18:32:13 +00002433
reeda2217ef2016-07-20 06:04:34 -07002434 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002435 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2436 *paint);
2437 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002438 special = this->getDevice()->makeSpecial(bitmap);
2439 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002440 drawAsSprite = false;
2441 }
2442 }
2443
reed262a71b2015-12-05 13:07:27 -08002444 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002445
2446 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002447 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002448 if (special) {
reed262a71b2015-12-05 13:07:27 -08002449 SkPoint pt;
2450 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002451 iter.fDevice->drawSpecial(iter, special.get(),
2452 SkScalarRoundToInt(pt.fX),
2453 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002454 } else {
2455 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2456 }
reed33366972015-10-08 09:22:02 -07002457 }
msarettfbfa2582016-08-12 08:29:08 -07002458
reed33366972015-10-08 09:22:02 -07002459 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002460}
2461
reed@google.com9987ec32011-09-07 11:57:52 +00002462// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002463void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002464 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002465 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002466 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002467 return;
2468 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002469
halcanary96fcdcc2015-08-27 07:41:13 -07002470 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002471 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002472 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2473 return;
2474 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002475 }
reed@google.com3d608122011-11-21 15:16:16 +00002476
reed@google.com33535f32012-09-25 15:37:50 +00002477 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002478 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002479 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002481
senorblancoc41e7e12015-12-07 12:51:30 -08002482 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002483 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002484
reed@google.com33535f32012-09-25 15:37:50 +00002485 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002486 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002487 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002488
reed@google.com33535f32012-09-25 15:37:50 +00002489 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002490}
2491
reed41af9662015-01-05 07:49:08 -08002492void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002493 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002494 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002495 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002496 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002497}
2498
reed4c21dc52015-06-25 12:32:03 -07002499void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2500 const SkPaint* paint) {
2501 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002502
halcanary96fcdcc2015-08-27 07:41:13 -07002503 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002504 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002505 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2506 return;
2507 }
reed@google.com3d608122011-11-21 15:16:16 +00002508 }
halcanary9d524f22016-03-29 09:03:52 -07002509
reed4c21dc52015-06-25 12:32:03 -07002510 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002511 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002512 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002513 }
halcanary9d524f22016-03-29 09:03:52 -07002514
senorblancoc41e7e12015-12-07 12:51:30 -08002515 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002516
reed4c21dc52015-06-25 12:32:03 -07002517 while (iter.next()) {
2518 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002519 }
halcanary9d524f22016-03-29 09:03:52 -07002520
reed4c21dc52015-06-25 12:32:03 -07002521 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002522}
2523
reed41af9662015-01-05 07:49:08 -08002524void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2525 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002526 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002527 SkDEBUGCODE(bitmap.validate();)
2528
halcanary96fcdcc2015-08-27 07:41:13 -07002529 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002530 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002531 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2532 return;
2533 }
reed4c21dc52015-06-25 12:32:03 -07002534 }
halcanary9d524f22016-03-29 09:03:52 -07002535
reed4c21dc52015-06-25 12:32:03 -07002536 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002537 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002538 paint = lazy.init();
2539 }
halcanary9d524f22016-03-29 09:03:52 -07002540
senorblancoc41e7e12015-12-07 12:51:30 -08002541 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002542
reed4c21dc52015-06-25 12:32:03 -07002543 while (iter.next()) {
2544 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2545 }
halcanary9d524f22016-03-29 09:03:52 -07002546
reed4c21dc52015-06-25 12:32:03 -07002547 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002548}
2549
msarett16882062016-08-16 09:31:08 -07002550void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2551 const SkPaint* paint) {
2552 if (nullptr == paint || paint->canComputeFastBounds()) {
2553 SkRect storage;
2554 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2555 return;
2556 }
2557 }
2558
2559 SkLazyPaint lazy;
2560 if (nullptr == paint) {
2561 paint = lazy.init();
2562 }
2563
2564 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2565
2566 while (iter.next()) {
2567 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2568 }
2569
2570 LOOPER_END
2571}
2572
2573void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2574 const SkRect& dst, const SkPaint* paint) {
2575 if (nullptr == paint || paint->canComputeFastBounds()) {
2576 SkRect storage;
2577 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2578 return;
2579 }
2580 }
2581
2582 SkLazyPaint lazy;
2583 if (nullptr == paint) {
2584 paint = lazy.init();
2585 }
2586
2587 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2588
2589 while (iter.next()) {
2590 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2591 }
2592
2593 LOOPER_END
2594}
2595
reed@google.comf67e4cf2011-03-15 20:56:58 +00002596class SkDeviceFilteredPaint {
2597public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002598 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002599 uint32_t filteredFlags = device->filterTextFlags(paint);
2600 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002601 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002602 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002603 fPaint = newPaint;
2604 } else {
2605 fPaint = &paint;
2606 }
2607 }
2608
reed@google.comf67e4cf2011-03-15 20:56:58 +00002609 const SkPaint& paint() const { return *fPaint; }
2610
2611private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002612 const SkPaint* fPaint;
2613 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002614};
2615
bungeman@google.com52c748b2011-08-22 21:30:43 +00002616void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2617 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002618 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002619 draw.fDevice->drawRect(draw, r, paint);
2620 } else {
2621 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002622 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002623 draw.fDevice->drawRect(draw, r, p);
2624 }
2625}
2626
2627void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2628 const char text[], size_t byteLength,
2629 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002630 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002631
2632 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002633 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002634 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002635 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002636 return;
2637 }
2638
2639 SkScalar width = 0;
2640 SkPoint start;
2641
2642 start.set(0, 0); // to avoid warning
2643 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2644 SkPaint::kStrikeThruText_Flag)) {
2645 width = paint.measureText(text, byteLength);
2646
2647 SkScalar offsetX = 0;
2648 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2649 offsetX = SkScalarHalf(width);
2650 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2651 offsetX = width;
2652 }
2653 start.set(x - offsetX, y);
2654 }
2655
2656 if (0 == width) {
2657 return;
2658 }
2659
2660 uint32_t flags = paint.getFlags();
2661
2662 if (flags & (SkPaint::kUnderlineText_Flag |
2663 SkPaint::kStrikeThruText_Flag)) {
2664 SkScalar textSize = paint.getTextSize();
2665 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2666 SkRect r;
2667
2668 r.fLeft = start.fX;
2669 r.fRight = start.fX + width;
2670
2671 if (flags & SkPaint::kUnderlineText_Flag) {
2672 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2673 start.fY);
2674 r.fTop = offset;
2675 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002676 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002677 }
2678 if (flags & SkPaint::kStrikeThruText_Flag) {
2679 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2680 start.fY);
2681 r.fTop = offset;
2682 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002683 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002684 }
2685 }
2686}
2687
reed@google.come0d9ce82014-04-23 04:00:17 +00002688void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2689 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002690 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002691
2692 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002693 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002694 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002695 DrawTextDecorations(iter, dfp.paint(),
2696 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 }
2698
reed@google.com4e2b3d32011-04-07 14:18:59 +00002699 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002700}
2701
reed@google.come0d9ce82014-04-23 04:00:17 +00002702void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2703 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002704 SkPoint textOffset = SkPoint::Make(0, 0);
2705
halcanary96fcdcc2015-08-27 07:41:13 -07002706 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002707
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002709 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002710 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002711 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002712 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002713
reed@google.com4e2b3d32011-04-07 14:18:59 +00002714 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002715}
2716
reed@google.come0d9ce82014-04-23 04:00:17 +00002717void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2718 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002719
2720 SkPoint textOffset = SkPoint::Make(0, constY);
2721
halcanary96fcdcc2015-08-27 07:41:13 -07002722 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002723
reed@android.com8a1c16f2008-12-17 15:59:43 +00002724 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002725 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002726 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002727 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002729
reed@google.com4e2b3d32011-04-07 14:18:59 +00002730 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002731}
2732
reed@google.come0d9ce82014-04-23 04:00:17 +00002733void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2734 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002735 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002736
reed@android.com8a1c16f2008-12-17 15:59:43 +00002737 while (iter.next()) {
2738 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002739 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002741
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002742 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002743}
2744
reed45561a02016-07-07 12:47:17 -07002745void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2746 const SkRect* cullRect, const SkPaint& paint) {
2747 if (cullRect && this->quickReject(*cullRect)) {
2748 return;
2749 }
2750
2751 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2752
2753 while (iter.next()) {
2754 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2755 }
2756
2757 LOOPER_END
2758}
2759
fmalita00d5c2c2014-08-21 08:53:26 -07002760void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2761 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002762
fmalita85d5eb92015-03-04 11:20:12 -08002763 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002764 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002765 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002766 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002767 SkRect tmp;
2768 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2769 return;
2770 }
2771 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002772 }
2773
fmalita024f9962015-03-03 19:08:17 -08002774 // We cannot filter in the looper as we normally do, because the paint is
2775 // incomplete at this point (text-related attributes are embedded within blob run paints).
2776 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002777 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002778
fmalita85d5eb92015-03-04 11:20:12 -08002779 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002780
fmalitaaa1b9122014-08-28 14:32:24 -07002781 while (iter.next()) {
2782 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002783 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002784 }
2785
fmalitaaa1b9122014-08-28 14:32:24 -07002786 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002787
2788 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002789}
2790
reed@google.come0d9ce82014-04-23 04:00:17 +00002791// These will become non-virtual, so they always call the (virtual) onDraw... method
2792void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2793 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002794 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002795 if (byteLength) {
2796 this->onDrawText(text, byteLength, x, y, paint);
2797 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002798}
2799void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2800 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002801 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002802 if (byteLength) {
2803 this->onDrawPosText(text, byteLength, pos, paint);
2804 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002805}
2806void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2807 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002808 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002809 if (byteLength) {
2810 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2811 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002812}
2813void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2814 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002816 if (byteLength) {
2817 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2818 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002819}
reed45561a02016-07-07 12:47:17 -07002820void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2821 const SkRect* cullRect, const SkPaint& paint) {
2822 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2823 if (byteLength) {
2824 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2825 }
2826}
fmalita00d5c2c2014-08-21 08:53:26 -07002827void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2828 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002829 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002830 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002831 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002832}
reed@google.come0d9ce82014-04-23 04:00:17 +00002833
reed41af9662015-01-05 07:49:08 -08002834void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2835 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002836 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002837 const uint16_t indices[], int indexCount,
2838 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002839 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002840 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002841
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842 while (iter.next()) {
2843 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002844 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002845 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002846 }
reed@google.com4b226022011-01-11 18:32:13 +00002847
reed@google.com4e2b3d32011-04-07 14:18:59 +00002848 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849}
2850
dandovb3c9d1c2014-08-12 08:34:29 -07002851void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002852 const SkPoint texCoords[4], SkBlendMode bmode,
2853 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002854 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002855 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002856 return;
2857 }
mtklein6cfa73a2014-08-13 13:33:49 -07002858
Mike Reedfaba3712016-11-03 14:45:31 -04002859 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002860}
2861
2862void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002863 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002864 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002865 // Since a patch is always within the convex hull of the control points, we discard it when its
2866 // bounding rectangle is completely outside the current clip.
2867 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002868 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002869 if (this->quickReject(bounds)) {
2870 return;
2871 }
mtklein6cfa73a2014-08-13 13:33:49 -07002872
halcanary96fcdcc2015-08-27 07:41:13 -07002873 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002874
dandovecfff212014-08-04 10:02:00 -07002875 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002876 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002877 }
mtklein6cfa73a2014-08-13 13:33:49 -07002878
dandovecfff212014-08-04 10:02:00 -07002879 LOOPER_END
2880}
2881
reeda8db7282015-07-07 10:22:31 -07002882void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002883 RETURN_ON_NULL(dr);
2884 if (x || y) {
2885 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2886 this->onDrawDrawable(dr, &matrix);
2887 } else {
2888 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002889 }
2890}
2891
reeda8db7282015-07-07 10:22:31 -07002892void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002893 RETURN_ON_NULL(dr);
2894 if (matrix && matrix->isIdentity()) {
2895 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002896 }
reede3b38ce2016-01-08 09:18:44 -08002897 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002898}
2899
2900void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002901 // drawable bounds are no longer reliable (e.g. android displaylist)
2902 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002903 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002904}
2905
reed71c3c762015-06-24 10:29:17 -07002906void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002907 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002908 const SkRect* cull, const SkPaint* paint) {
2909 if (cull && this->quickReject(*cull)) {
2910 return;
2911 }
2912
2913 SkPaint pnt;
2914 if (paint) {
2915 pnt = *paint;
2916 }
halcanary9d524f22016-03-29 09:03:52 -07002917
halcanary96fcdcc2015-08-27 07:41:13 -07002918 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002919 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002920 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002921 }
2922 LOOPER_END
2923}
2924
reedf70b5312016-03-04 16:36:20 -08002925void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2926 SkASSERT(key);
2927
2928 SkPaint paint;
2929 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2930 while (iter.next()) {
2931 iter.fDevice->drawAnnotation(iter, rect, key, value);
2932 }
2933 LOOPER_END
2934}
2935
reed@android.com8a1c16f2008-12-17 15:59:43 +00002936//////////////////////////////////////////////////////////////////////////////
2937// These methods are NOT virtual, and therefore must call back into virtual
2938// methods, rather than actually drawing themselves.
2939//////////////////////////////////////////////////////////////////////////////
2940
reed374772b2016-10-05 17:33:02 -07002941void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002942 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002943 SkPaint paint;
2944
2945 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002946 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002947 this->drawPaint(paint);
2948}
2949
reed374772b2016-10-05 17:33:02 -07002950void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002951 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002952 SkPaint paint;
2953
2954 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002955 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002956 this->drawPaint(paint);
2957}
2958
2959void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002960 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002961 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002962
reed@android.com8a1c16f2008-12-17 15:59:43 +00002963 pt.set(x, y);
2964 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2965}
2966
2967void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002968 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002969 SkPoint pt;
2970 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002971
reed@android.com8a1c16f2008-12-17 15:59:43 +00002972 pt.set(x, y);
2973 paint.setColor(color);
2974 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2975}
2976
2977void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2978 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002979 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002980 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002981
reed@android.com8a1c16f2008-12-17 15:59:43 +00002982 pts[0].set(x0, y0);
2983 pts[1].set(x1, y1);
2984 this->drawPoints(kLines_PointMode, 2, pts, paint);
2985}
2986
2987void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2988 SkScalar right, SkScalar bottom,
2989 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002990 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002991 SkRect r;
2992
2993 r.set(left, top, right, bottom);
2994 this->drawRect(r, paint);
2995}
2996
2997void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2998 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002999 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003000 if (radius < 0) {
3001 radius = 0;
3002 }
3003
3004 SkRect r;
3005 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003006 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003007}
3008
3009void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3010 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003011 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003012 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003013 SkRRect rrect;
3014 rrect.setRectXY(r, rx, ry);
3015 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003016 } else {
3017 this->drawRect(r, paint);
3018 }
3019}
3020
reed@android.com8a1c16f2008-12-17 15:59:43 +00003021void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3022 SkScalar sweepAngle, bool useCenter,
3023 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003024 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003025 if (oval.isEmpty() || !sweepAngle) {
3026 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003027 }
bsalomon21af9ca2016-08-25 12:29:23 -07003028 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003029}
3030
3031void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3032 const SkPath& path, SkScalar hOffset,
3033 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003034 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003035 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003036
reed@android.com8a1c16f2008-12-17 15:59:43 +00003037 matrix.setTranslate(hOffset, vOffset);
3038 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3039}
3040
reed@android.comf76bacf2009-05-13 14:00:33 +00003041///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003042
3043/**
3044 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3045 * against the playback cost of recursing into the subpicture to get at its actual ops.
3046 *
3047 * For now we pick a conservatively small value, though measurement (and other heuristics like
3048 * the type of ops contained) may justify changing this value.
3049 */
3050#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003051
reedd5fa1a42014-08-09 11:08:05 -07003052void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003053 RETURN_ON_NULL(picture);
3054
reed1c2c4412015-04-30 13:09:24 -07003055 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003056 if (matrix && matrix->isIdentity()) {
3057 matrix = nullptr;
3058 }
3059 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3060 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3061 picture->playback(this);
3062 } else {
3063 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003064 }
3065}
robertphillips9b14f262014-06-04 05:40:44 -07003066
reedd5fa1a42014-08-09 11:08:05 -07003067void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3068 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003069 if (!paint || paint->canComputeFastBounds()) {
3070 SkRect bounds = picture->cullRect();
3071 if (paint) {
3072 paint->computeFastBounds(bounds, &bounds);
3073 }
3074 if (matrix) {
3075 matrix->mapRect(&bounds);
3076 }
3077 if (this->quickReject(bounds)) {
3078 return;
3079 }
3080 }
3081
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003082 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003083 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003084}
3085
vjiaoblack95302da2016-07-21 10:25:54 -07003086#ifdef SK_EXPERIMENTAL_SHADOWING
3087void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3088 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003089 const SkPaint* paint,
3090 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003091 RETURN_ON_NULL(picture);
3092
3093 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3094
vjiaoblacke6f5d562016-08-25 06:30:23 -07003095 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003096}
3097
3098void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3099 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003100 const SkPaint* paint,
3101 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003102 if (!paint || paint->canComputeFastBounds()) {
3103 SkRect bounds = picture->cullRect();
3104 if (paint) {
3105 paint->computeFastBounds(bounds, &bounds);
3106 }
3107 if (matrix) {
3108 matrix->mapRect(&bounds);
3109 }
3110 if (this->quickReject(bounds)) {
3111 return;
3112 }
3113 }
3114
3115 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3116
vjiaoblacke6f5d562016-08-25 06:30:23 -07003117 sk_sp<SkImage> povDepthMap;
3118 sk_sp<SkImage> diffuseMap;
3119
vjiaoblack904527d2016-08-09 09:32:09 -07003120 // povDepthMap
3121 {
3122 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003123 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3124 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003125 sk_sp<SkLights> povLight = builder.finish();
3126
3127 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3128 picture->cullRect().height(),
3129 kBGRA_8888_SkColorType,
3130 kOpaque_SkAlphaType);
3131
3132 // Create a new surface (that matches the backend of canvas)
3133 // to create the povDepthMap
3134 sk_sp<SkSurface> surf(this->makeSurface(info));
3135
3136 // Wrap another SPFCanvas around the surface
3137 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3138 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3139
3140 // set the depth map canvas to have the light as the user's POV
3141 depthMapCanvas->setLights(std::move(povLight));
3142
3143 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003144 povDepthMap = surf->makeImageSnapshot();
3145 }
3146
3147 // diffuseMap
3148 {
3149 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3150 picture->cullRect().height(),
3151 kBGRA_8888_SkColorType,
3152 kOpaque_SkAlphaType);
3153
3154 sk_sp<SkSurface> surf(this->makeSurface(info));
3155 surf->getCanvas()->drawPicture(picture);
3156
3157 diffuseMap = surf->makeImageSnapshot();
3158 }
vjiaoblack904527d2016-08-09 09:32:09 -07003159
3160 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3161 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003162 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3163 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003164
3165 // TODO: pass the depth to the shader in vertices, or uniforms
3166 // so we don't have to render depth and color separately
3167 for (int i = 0; i < fLights->numLights(); ++i) {
3168 // skip over ambient lights; they don't cast shadows
3169 // lights that have shadow maps do not need updating (because lights are immutable)
3170 sk_sp<SkImage> depthMap;
3171 SkISize shMapSize;
3172
3173 if (fLights->light(i).getShadowMap() != nullptr) {
3174 continue;
3175 }
3176
3177 if (fLights->light(i).isRadial()) {
3178 shMapSize.fHeight = 1;
3179 shMapSize.fWidth = (int) picture->cullRect().width();
3180
3181 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3182 kBGRA_8888_SkColorType,
3183 kOpaque_SkAlphaType);
3184
3185 // Create new surface (that matches the backend of canvas)
3186 // for each shadow map
3187 sk_sp<SkSurface> surf(this->makeSurface(info));
3188
3189 // Wrap another SPFCanvas around the surface
3190 SkCanvas* depthMapCanvas = surf->getCanvas();
3191
3192 SkLights::Builder builder;
3193 builder.add(fLights->light(i));
3194 sk_sp<SkLights> curLight = builder.finish();
3195
3196 sk_sp<SkShader> shadowMapShader;
3197 shadowMapShader = SkRadialShadowMapShader::Make(
3198 povDepthShader, curLight,
3199 (int) picture->cullRect().width(),
3200 (int) picture->cullRect().height());
3201
3202 SkPaint shadowMapPaint;
3203 shadowMapPaint.setShader(std::move(shadowMapShader));
3204
3205 depthMapCanvas->setLights(curLight);
3206
3207 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3208 diffuseMap->height()),
3209 shadowMapPaint);
3210
3211 depthMap = surf->makeImageSnapshot();
3212
3213 } else {
3214 // TODO: compute the correct size of the depth map from the light properties
3215 // TODO: maybe add a kDepth_8_SkColorType
3216 // TODO: find actual max depth of picture
3217 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3218 fLights->light(i), 255,
3219 (int) picture->cullRect().width(),
3220 (int) picture->cullRect().height());
3221
3222 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3223 kBGRA_8888_SkColorType,
3224 kOpaque_SkAlphaType);
3225
3226 // Create a new surface (that matches the backend of canvas)
3227 // for each shadow map
3228 sk_sp<SkSurface> surf(this->makeSurface(info));
3229
3230 // Wrap another SPFCanvas around the surface
3231 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3232 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3233 depthMapCanvas->setShadowParams(params);
3234
3235 // set the depth map canvas to have the light we're drawing.
3236 SkLights::Builder builder;
3237 builder.add(fLights->light(i));
3238 sk_sp<SkLights> curLight = builder.finish();
3239 depthMapCanvas->setLights(std::move(curLight));
3240
3241 depthMapCanvas->drawPicture(picture);
3242 depthMap = surf->makeImageSnapshot();
3243 }
3244
3245 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3246 fLights->light(i).setShadowMap(std::move(depthMap));
3247 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3248 // we blur the variance map
3249 SkPaint blurPaint;
3250 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3251 params.fShadowRadius, nullptr));
3252
3253 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3254 kBGRA_8888_SkColorType,
3255 kOpaque_SkAlphaType);
3256
3257 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3258
3259 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3260
3261 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3262 }
3263 }
3264
3265 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003266 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3267 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003268 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003269 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003270 diffuseMap->height(),
3271 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003272
3273 shadowPaint.setShader(shadowShader);
3274
3275 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003276}
3277#endif
3278
reed@android.com8a1c16f2008-12-17 15:59:43 +00003279///////////////////////////////////////////////////////////////////////////////
3280///////////////////////////////////////////////////////////////////////////////
3281
reed3aafe112016-08-18 12:45:34 -07003282SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003283 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003284
3285 SkASSERT(canvas);
3286
reed3aafe112016-08-18 12:45:34 -07003287 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003288 fDone = !fImpl->next();
3289}
3290
3291SkCanvas::LayerIter::~LayerIter() {
3292 fImpl->~SkDrawIter();
3293}
3294
3295void SkCanvas::LayerIter::next() {
3296 fDone = !fImpl->next();
3297}
3298
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003299SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003300 return fImpl->getDevice();
3301}
3302
3303const SkMatrix& SkCanvas::LayerIter::matrix() const {
3304 return fImpl->getMatrix();
3305}
3306
3307const SkPaint& SkCanvas::LayerIter::paint() const {
3308 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003309 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003310 paint = &fDefaultPaint;
3311 }
3312 return *paint;
3313}
3314
reed1e7f5e72016-04-27 07:49:17 -07003315const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003316int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3317int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003318
3319///////////////////////////////////////////////////////////////////////////////
3320
fmalitac3b589a2014-06-05 12:40:07 -07003321SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003322
3323///////////////////////////////////////////////////////////////////////////////
3324
3325static bool supported_for_raster_canvas(const SkImageInfo& info) {
3326 switch (info.alphaType()) {
3327 case kPremul_SkAlphaType:
3328 case kOpaque_SkAlphaType:
3329 break;
3330 default:
3331 return false;
3332 }
3333
3334 switch (info.colorType()) {
3335 case kAlpha_8_SkColorType:
3336 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003337 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003338 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003339 break;
3340 default:
3341 return false;
3342 }
3343
3344 return true;
3345}
3346
Mike Reed5df49342016-11-12 08:06:55 -06003347std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3348 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003349 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003350 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003351 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003352
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003353 SkBitmap bitmap;
3354 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003355 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003356 }
Mike Reed5df49342016-11-12 08:06:55 -06003357 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003358}
reedd5fa1a42014-08-09 11:08:05 -07003359
3360///////////////////////////////////////////////////////////////////////////////
3361
3362SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003363 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003364 : fCanvas(canvas)
3365 , fSaveCount(canvas->getSaveCount())
3366{
bsalomon49f085d2014-09-05 13:34:00 -07003367 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003368 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003369 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003370 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003371 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003372 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003373 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003374 canvas->save();
3375 }
mtklein6cfa73a2014-08-13 13:33:49 -07003376
bsalomon49f085d2014-09-05 13:34:00 -07003377 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003378 canvas->concat(*matrix);
3379 }
3380}
3381
3382SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3383 fCanvas->restoreToCount(fSaveCount);
3384}
reede8f30622016-03-23 18:59:25 -07003385
Florin Malitaee424ac2016-12-01 12:47:59 -05003386///////////////////////////////////////////////////////////////////////////////
3387
3388SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3389 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3390
Florin Malita439ace92016-12-02 12:05:41 -05003391SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3392 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3393
Florin Malitaee424ac2016-12-01 12:47:59 -05003394SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3395 (void)this->INHERITED::getSaveLayerStrategy(rec);
3396 return kNoLayer_SaveLayerStrategy;
3397}
3398
3399///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003400
reed73603f32016-09-20 08:42:38 -07003401static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3402static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3403static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3404static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3405static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3406static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");