blob: 0fdbc5838dc995e0a4d7bfad002bc61efbfd6192 [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"
reed262a71b2015-12-05 13:07:27 -080022#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000023#include "SkMetaData.h"
msarettfbfa2582016-08-12 08:29:08 -070024#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070025#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070026#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000027#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070028#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000029#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080030#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000031#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070032#include "SkShadowPaintFilterCanvas.h"
33#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000034#include "SkSmallAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000036#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070037#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000038#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000039#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080040#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070041#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000042
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000043#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080044#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070046#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070047
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#endif
49
reede3b38ce2016-01-08 09:18:44 -080050#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
51
reedc83a2972015-07-16 07:40:45 -070052/*
53 * Return true if the drawing this rect would hit every pixels in the canvas.
54 *
55 * Returns false if
56 * - rect does not contain the canvas' bounds
57 * - paint is not fill
58 * - paint would blur or otherwise change the coverage of the rect
59 */
60bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
61 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070062 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
63 (int)kNone_ShaderOverrideOpacity,
64 "need_matching_enums0");
65 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
66 (int)kOpaque_ShaderOverrideOpacity,
67 "need_matching_enums1");
68 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
69 (int)kNotOpaque_ShaderOverrideOpacity,
70 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070071
72 const SkISize size = this->getBaseLayerSize();
73 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
74 if (!this->getClipStack()->quickContains(bounds)) {
75 return false;
76 }
77
78 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070079 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070080 return false; // conservative
81 }
halcanaryc5769b22016-08-10 07:13:21 -070082
83 SkRect devRect;
84 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
85 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070086 return false;
87 }
88 }
89
90 if (paint) {
91 SkPaint::Style paintStyle = paint->getStyle();
92 if (!(paintStyle == SkPaint::kFill_Style ||
93 paintStyle == SkPaint::kStrokeAndFill_Style)) {
94 return false;
95 }
96 if (paint->getMaskFilter() || paint->getLooper()
97 || paint->getPathEffect() || paint->getImageFilter()) {
98 return false; // conservative
99 }
100 }
101 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
102}
103
104///////////////////////////////////////////////////////////////////////////////////////////////////
105
reedd990e2f2014-12-22 11:58:30 -0800106static bool gIgnoreSaveLayerBounds;
107void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
108 gIgnoreSaveLayerBounds = ignore;
109}
110bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
111 return gIgnoreSaveLayerBounds;
112}
113
reed0acf1b42014-12-22 16:12:38 -0800114static bool gTreatSpriteAsBitmap;
115void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
116 gTreatSpriteAsBitmap = spriteAsBitmap;
117}
118bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
119 return gTreatSpriteAsBitmap;
120}
121
reed@google.comda17f752012-08-16 18:27:05 +0000122// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123//#define SK_TRACE_SAVERESTORE
124
125#ifdef SK_TRACE_SAVERESTORE
126 static int gLayerCounter;
127 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
128 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
129
130 static int gRecCounter;
131 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
132 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
133
134 static int gCanvasCounter;
135 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
136 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
137#else
138 #define inc_layer()
139 #define dec_layer()
140 #define inc_rec()
141 #define dec_rec()
142 #define inc_canvas()
143 #define dec_canvas()
144#endif
145
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000146typedef SkTLazy<SkPaint> SkLazyPaint;
147
reedc83a2972015-07-16 07:40:45 -0700148void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000149 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700150 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
151 ? SkSurface::kDiscard_ContentChangeMode
152 : SkSurface::kRetain_ContentChangeMode);
153 }
154}
155
156void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
157 ShaderOverrideOpacity overrideOpacity) {
158 if (fSurfaceBase) {
159 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
160 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
161 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
162 // and therefore we don't care which mode we're in.
163 //
164 if (fSurfaceBase->outstandingImageSnapshot()) {
165 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
166 mode = SkSurface::kDiscard_ContentChangeMode;
167 }
168 }
169 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000170 }
171}
172
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000175/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 The clip/matrix/proc are fields that reflect the top of the save/restore
177 stack. Whenever the canvas changes, it marks a dirty flag, and then before
178 these are used (assuming we're not on a layer) we rebuild these cache
179 values: they reflect the top of the save stack, but translated and clipped
180 by the device's XY offset and bitmap-bounds.
181*/
182struct DeviceCM {
183 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000184 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000185 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000186 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700187 const SkMatrix* fMatrix;
188 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700189 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190
reed96e657d2015-03-10 17:30:07 -0700191 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700192 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700193 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700194 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700195 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700196 {
reed2c9e2002016-07-25 08:05:22 -0700197 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000198 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700199 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000200 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000202 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700203 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700204 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000205 }
reed@google.com4b226022011-01-11 18:32:13 +0000206
mtkleinfeaadee2015-04-08 11:25:48 -0700207 void reset(const SkIRect& bounds) {
208 SkASSERT(!fPaint);
209 SkASSERT(!fNext);
210 SkASSERT(fDevice);
211 fClip.setRect(bounds);
212 }
213
reed@google.com045e62d2011-10-24 12:19:46 +0000214 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700215 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000216 int x = fDevice->getOrigin().x();
217 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 int width = fDevice->width();
219 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000220
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 if ((x | y) == 0) {
222 fMatrix = &totalMatrix;
223 fClip = totalClip;
224 } else {
225 fMatrixStorage = totalMatrix;
226 fMatrixStorage.postTranslate(SkIntToScalar(-x),
227 SkIntToScalar(-y));
228 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000229
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 totalClip.translate(-x, -y, &fClip);
231 }
232
reed@google.com045e62d2011-10-24 12:19:46 +0000233 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234
235 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000236
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000238 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 SkRegion::kDifference_Op);
240 }
reed@google.com4b226022011-01-11 18:32:13 +0000241
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242#ifdef SK_DEBUG
243 if (!fClip.isEmpty()) {
244 SkIRect deviceR;
245 deviceR.set(0, 0, width, height);
246 SkASSERT(deviceR.contains(fClip.getBounds()));
247 }
248#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000249 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250};
251
252/* This is the record we keep for each save/restore level in the stack.
253 Since a level optionally copies the matrix and/or stack, we have pointers
254 for these fields. If the value is copied for this level, the copy is
255 stored in the ...Storage field, and the pointer points to that. If the
256 value is not copied for this level, we ignore ...Storage, and just point
257 at the corresponding value in the previous level in the stack.
258*/
259class SkCanvas::MCRec {
260public:
reed1f836ee2014-07-07 07:49:34 -0700261 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700262 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 /* If there are any layers in the stack, this points to the top-most
264 one that is at or below this level in the stack (so we know what
265 bitmap/device to draw into from this level. This value is NOT
266 reference counted, since the real owner is either our fLayer field,
267 or a previous one in a lower level.)
268 */
reed2ff1fce2014-12-11 07:07:37 -0800269 DeviceCM* fTopLayer;
270 SkRasterClip fRasterClip;
271 SkMatrix fMatrix;
272 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273
vjiaoblacke5de1302016-07-13 14:05:28 -0700274 // This is the current cumulative depth (aggregate of all done translateZ calls)
275 SkScalar fCurDrawDepth;
276
reedd9544982014-09-09 18:46:22 -0700277 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700278 fFilter = nullptr;
279 fLayer = nullptr;
280 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800281 fMatrix.reset();
282 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700283 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700284
reedd9544982014-09-09 18:46:22 -0700285 // don't bother initializing fNext
286 inc_rec();
287 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700288 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
289 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700290 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700291 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700292 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800293 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700294
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 // don't bother initializing fNext
296 inc_rec();
297 }
298 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000299 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700300 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 dec_rec();
302 }
mtkleinfeaadee2015-04-08 11:25:48 -0700303
304 void reset(const SkIRect& bounds) {
305 SkASSERT(fLayer);
306 SkASSERT(fDeferredSaveCount == 0);
307
308 fMatrix.reset();
309 fRasterClip.setRect(bounds);
310 fLayer->reset(bounds);
311 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312};
313
reed02f9ed72016-09-06 09:06:18 -0700314static SkIRect compute_device_bounds(SkBaseDevice* device) {
315 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
316 device->width(), device->height());
317}
318
reed@android.com8a1c16f2008-12-17 15:59:43 +0000319class SkDrawIter : public SkDraw {
320public:
reed3aafe112016-08-18 12:45:34 -0700321 SkDrawIter(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 canvas->updateDeviceCMCache();
323
bungeman6bd52842016-10-27 09:30:08 -0700324 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700326
327 fMultiDeviceCS = nullptr;
328 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700329 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700330 fMultiDeviceCS->save();
331 }
332 }
333
334 ~SkDrawIter() {
335 if (fMultiDeviceCS) {
336 fMultiDeviceCS->restore();
337 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 }
reed@google.com4b226022011-01-11 18:32:13 +0000339
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700341 if (fMultiDeviceCS && fDevice) {
342 // remove the previous device's bounds
reed73603f32016-09-20 08:42:38 -0700343 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), SkCanvas::kDifference_Op);
reed02f9ed72016-09-06 09:06:18 -0700344 }
345
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700347 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
348 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 }
350
reed@google.comf68c5e22012-02-24 16:38:58 +0000351 const DeviceCM* rec = fCurrLayer;
352 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353
354 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000355 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700357 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700358 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700359 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000361 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362
363 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700364 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000365
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366 return true;
367 }
368 return false;
369 }
reed@google.com4b226022011-01-11 18:32:13 +0000370
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000371 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700372 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000373 int getX() const { return fDevice->getOrigin().x(); }
374 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000377
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 const DeviceCM* fCurrLayer;
380 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700381 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382
383 typedef SkDraw INHERITED;
384};
385
386/////////////////////////////////////////////////////////////////////////////
387
reeddbc3cef2015-04-29 12:18:57 -0700388static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
389 return lazy->isValid() ? lazy->get() : lazy->set(orig);
390}
391
392/**
393 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700394 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700395 */
reedd053ce92016-03-22 10:17:23 -0700396static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700397 SkImageFilter* imgf = paint.getImageFilter();
398 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700399 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700400 }
401
reedd053ce92016-03-22 10:17:23 -0700402 SkColorFilter* imgCFPtr;
403 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700404 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700405 }
reedd053ce92016-03-22 10:17:23 -0700406 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700407
408 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700409 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700410 // there is no existing paint colorfilter, so we can just return the imagefilter's
411 return imgCF;
412 }
413
414 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
415 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700416 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700417}
418
senorblanco87e066e2015-10-28 11:23:36 -0700419/**
420 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
421 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
422 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
423 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
424 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
425 * conservative "effective" bounds based on the settings in the paint... with one exception. This
426 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
427 * deliberately ignored.
428 */
429static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
430 const SkRect& rawBounds,
431 SkRect* storage) {
432 SkPaint tmpUnfiltered(paint);
433 tmpUnfiltered.setImageFilter(nullptr);
434 if (tmpUnfiltered.canComputeFastBounds()) {
435 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
436 } else {
437 return rawBounds;
438 }
439}
440
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441class AutoDrawLooper {
442public:
senorblanco87e066e2015-10-28 11:23:36 -0700443 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
444 // paint. It's used to determine the size of the offscreen layer for filters.
445 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700446 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700447 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000448 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800449#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800451#else
452 fFilter = nullptr;
453#endif
reed4a8126e2014-09-22 07:29:03 -0700454 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000455 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700456 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000457 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458
reedd053ce92016-03-22 10:17:23 -0700459 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700460 if (simplifiedCF) {
461 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700462 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700463 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700464 fPaint = paint;
465 }
466
467 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700468 /**
469 * We implement ImageFilters for a given draw by creating a layer, then applying the
470 * imagefilter to the pixels of that layer (its backing surface/image), and then
471 * we call restore() to xfer that layer to the main canvas.
472 *
473 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
474 * 2. Generate the src pixels:
475 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
476 * return (fPaint). We then draw the primitive (using srcover) into a cleared
477 * buffer/surface.
478 * 3. Restore the layer created in #1
479 * The imagefilter is passed the buffer/surface from the layer (now filled with the
480 * src pixels of the primitive). It returns a new "filtered" buffer, which we
481 * draw onto the previous layer using the xfermode from the original paint.
482 */
reed@google.com8926b162012-03-23 15:36:36 +0000483 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700484 tmp.setImageFilter(fPaint->getImageFilter());
reed374772b2016-10-05 17:33:02 -0700485 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700486 SkRect storage;
487 if (rawBounds) {
488 // Make rawBounds include all paint outsets except for those due to image filters.
489 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
490 }
reedbfd5f172016-01-07 11:28:08 -0800491 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700492 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700493 fTempLayerForImageFilter = true;
494 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000495 }
496
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000497 if (SkDrawLooper* looper = paint.getLooper()) {
498 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
499 looper->contextSize());
500 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000501 fIsSimple = false;
502 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700503 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000504 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700505 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000506 }
507 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000508
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700510 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000511 fCanvas->internalRestore();
512 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000513 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@google.com4e2b3d32011-04-07 14:18:59 +0000516 const SkPaint& paint() const {
517 SkASSERT(fPaint);
518 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000520
reed@google.com129ec222012-05-15 13:24:09 +0000521 bool next(SkDrawFilter::Type drawType) {
522 if (fDone) {
523 return false;
524 } else if (fIsSimple) {
525 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000526 return !fPaint->nothingToDraw();
527 } else {
528 return this->doNext(drawType);
529 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000530 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000531
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532private:
reeddbc3cef2015-04-29 12:18:57 -0700533 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
534 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000535 SkCanvas* fCanvas;
536 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000537 SkDrawFilter* fFilter;
538 const SkPaint* fPaint;
539 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700540 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000541 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000542 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000543 SkDrawLooper::Context* fLooperContext;
544 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000545
546 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000547};
548
reed@google.com129ec222012-05-15 13:24:09 +0000549bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700550 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000551 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700552 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000553
reeddbc3cef2015-04-29 12:18:57 -0700554 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
555 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000556
reed5c476fb2015-04-20 08:04:21 -0700557 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700558 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700559 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000560 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000561
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000562 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000563 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000564 return false;
565 }
566 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000567 if (!fFilter->filter(paint, drawType)) {
568 fDone = true;
569 return false;
570 }
halcanary96fcdcc2015-08-27 07:41:13 -0700571 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000572 // no looper means we only draw once
573 fDone = true;
574 }
575 }
576 fPaint = paint;
577
578 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000579 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000580 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000581 }
582
583 // call this after any possible paint modifiers
584 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700585 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000586 return false;
587 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000588 return true;
589}
590
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591////////// macros to place around the internal draw calls //////////////////
592
reed3aafe112016-08-18 12:45:34 -0700593#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
594 this->predrawNotify(); \
595 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
596 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800597 SkDrawIter iter(this);
598
599
reed@google.com8926b162012-03-23 15:36:36 +0000600#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000601 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700602 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000603 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000604 SkDrawIter iter(this);
605
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000606#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000607 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700608 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000609 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000610 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000611
reedc83a2972015-07-16 07:40:45 -0700612#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
613 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700614 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700615 while (looper.next(type)) { \
616 SkDrawIter iter(this);
617
reed@google.com4e2b3d32011-04-07 14:18:59 +0000618#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619
620////////////////////////////////////////////////////////////////////////////
621
msarettfbfa2582016-08-12 08:29:08 -0700622static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
623 if (bounds.isEmpty()) {
624 return SkRect::MakeEmpty();
625 }
626
627 // Expand bounds out by 1 in case we are anti-aliasing. We store the
628 // bounds as floats to enable a faster quick reject implementation.
629 SkRect dst;
630 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
631 return dst;
632}
633
mtkleinfeaadee2015-04-08 11:25:48 -0700634void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
635 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700636 fClipStack->reset();
637 fMCRec->reset(bounds);
638
639 // We're peering through a lot of structs here. Only at this scope do we
640 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
641 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700642 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700643 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700644}
645
reedd9544982014-09-09 18:46:22 -0700646SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800647 if (device && device->forceConservativeRasterClip()) {
648 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
649 }
650 // Since init() is only called once by our constructors, it is safe to perform this
651 // const-cast.
652 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
653
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000654 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700655 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800656 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700657 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700658#ifdef SK_EXPERIMENTAL_SHADOWING
659 fLights = nullptr;
660#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661
halcanary385fe4d2015-08-26 13:07:48 -0700662 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700663
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700665 new (fMCRec) MCRec(fConservativeRasterClip);
msarett9637ea92016-08-18 14:03:30 -0700666 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667
reeda499f902015-05-01 09:34:31 -0700668 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
669 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700670 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700671 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700672
reed@android.com8a1c16f2008-12-17 15:59:43 +0000673 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674
halcanary96fcdcc2015-08-27 07:41:13 -0700675 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000676
reedf92c8662014-08-18 08:02:43 -0700677 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700678 // The root device and the canvas should always have the same pixel geometry
679 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700680 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800681 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700682 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700683 }
msarettfbfa2582016-08-12 08:29:08 -0700684
reedf92c8662014-08-18 08:02:43 -0700685 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000686}
687
reed@google.comcde92112011-07-06 20:00:52 +0000688SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000689 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700690 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800691 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000692{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000693 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000694
halcanary96fcdcc2015-08-27 07:41:13 -0700695 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000696}
697
reedd9544982014-09-09 18:46:22 -0700698static SkBitmap make_nopixels(int width, int height) {
699 SkBitmap bitmap;
700 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
701 return bitmap;
702}
703
704class SkNoPixelsBitmapDevice : public SkBitmapDevice {
705public:
robertphillipsfcf78292015-06-19 11:49:52 -0700706 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
707 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800708 {
709 this->setOrigin(bounds.x(), bounds.y());
710 }
reedd9544982014-09-09 18:46:22 -0700711
712private:
piotaixrb5fae932014-09-24 13:03:30 -0700713
reedd9544982014-09-09 18:46:22 -0700714 typedef SkBitmapDevice INHERITED;
715};
716
reed96a857e2015-01-25 10:33:58 -0800717SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000718 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800719 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800720 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000721{
722 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700723
halcanary385fe4d2015-08-26 13:07:48 -0700724 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
725 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700726}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000727
reed78e27682014-11-19 08:04:34 -0800728SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700729 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700730 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800731 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700732{
733 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700734
halcanary385fe4d2015-08-26 13:07:48 -0700735 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700736}
737
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000738SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000739 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700740 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800741 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000742{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000743 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700744
reedd9544982014-09-09 18:46:22 -0700745 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746}
747
robertphillipsfcf78292015-06-19 11:49:52 -0700748SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
749 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700750 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800751 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700752{
753 inc_canvas();
754
755 this->init(device, flags);
756}
757
reed4a8126e2014-09-22 07:29:03 -0700758SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700759 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700760 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800761 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700762{
763 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700764
halcanary385fe4d2015-08-26 13:07:48 -0700765 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700766 this->init(device, kDefault_InitFlags);
767}
reed29c857d2014-09-21 10:25:07 -0700768
reed4a8126e2014-09-22 07:29:03 -0700769SkCanvas::SkCanvas(const SkBitmap& bitmap)
770 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
771 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800772 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700773{
774 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700775
halcanary385fe4d2015-08-26 13:07:48 -0700776 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700777 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000778}
779
780SkCanvas::~SkCanvas() {
781 // free up the contents of our deque
782 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000783
reed@android.com8a1c16f2008-12-17 15:59:43 +0000784 this->internalRestore(); // restore the last, since we're going away
785
halcanary385fe4d2015-08-26 13:07:48 -0700786 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000787
reed@android.com8a1c16f2008-12-17 15:59:43 +0000788 dec_canvas();
789}
790
fmalita53d9f1c2016-01-25 06:23:54 -0800791#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792SkDrawFilter* SkCanvas::getDrawFilter() const {
793 return fMCRec->fFilter;
794}
795
796SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700797 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000798 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
799 return filter;
800}
fmalita77650002016-01-21 18:47:11 -0800801#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000802
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000803SkMetaData& SkCanvas::getMetaData() {
804 // metadata users are rare, so we lazily allocate it. If that changes we
805 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700806 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000807 fMetaData = new SkMetaData;
808 }
809 return *fMetaData;
810}
811
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812///////////////////////////////////////////////////////////////////////////////
813
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000814void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700815 this->onFlush();
816}
817
818void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000819 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000820 if (device) {
821 device->flush();
822 }
823}
824
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000825SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000826 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000827 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
828}
829
senorblancoafc7cce2016-02-02 18:44:15 -0800830SkIRect SkCanvas::getTopLayerBounds() const {
831 SkBaseDevice* d = this->getTopDevice();
832 if (!d) {
833 return SkIRect::MakeEmpty();
834 }
835 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
836}
837
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000838SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000839 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000840 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841 SkASSERT(rec && rec->fLayer);
842 return rec->fLayer->fDevice;
843}
844
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000845SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000846 if (updateMatrixClip) {
847 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
848 }
reed@google.com9266fed2011-03-30 00:18:03 +0000849 return fMCRec->fTopLayer->fDevice;
850}
851
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000852bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700853 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000854 return false;
855 }
856
857 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700858 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700859 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000860 return false;
861 }
862 weAllocated = true;
863 }
864
reedcf01e312015-05-23 19:14:51 -0700865 SkAutoPixmapUnlock unlocker;
866 if (bitmap->requestLock(&unlocker)) {
867 const SkPixmap& pm = unlocker.pixmap();
868 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
869 return true;
870 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000871 }
872
873 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700874 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000875 }
876 return false;
877}
reed@google.com51df9e32010-12-23 19:29:18 +0000878
bsalomon@google.comc6980972011-11-02 19:57:21 +0000879bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000880 SkIRect r = srcRect;
881 const SkISize size = this->getBaseLayerSize();
882 if (!r.intersect(0, 0, size.width(), size.height())) {
883 bitmap->reset();
884 return false;
885 }
886
reed84825042014-09-02 12:50:45 -0700887 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000888 // bitmap will already be reset.
889 return false;
890 }
891 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
892 bitmap->reset();
893 return false;
894 }
895 return true;
896}
897
reed96472de2014-12-10 09:53:42 -0800898bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000899 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000900 if (!device) {
901 return false;
902 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000903 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800904
reed96472de2014-12-10 09:53:42 -0800905 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
906 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000907 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000908 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000909
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000910 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800911 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000912}
913
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000914bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700915 SkAutoPixmapUnlock unlocker;
916 if (bitmap.requestLock(&unlocker)) {
917 const SkPixmap& pm = unlocker.pixmap();
918 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000919 }
920 return false;
921}
922
923bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
924 int x, int y) {
925 switch (origInfo.colorType()) {
926 case kUnknown_SkColorType:
927 case kIndex_8_SkColorType:
928 return false;
929 default:
930 break;
931 }
halcanary96fcdcc2015-08-27 07:41:13 -0700932 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000933 return false;
934 }
935
936 const SkISize size = this->getBaseLayerSize();
937 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
938 if (!target.intersect(0, 0, size.width(), size.height())) {
939 return false;
940 }
941
942 SkBaseDevice* device = this->getDevice();
943 if (!device) {
944 return false;
945 }
946
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000947 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700948 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000949
950 // if x or y are negative, then we have to adjust pixels
951 if (x > 0) {
952 x = 0;
953 }
954 if (y > 0) {
955 y = 0;
956 }
957 // here x,y are either 0 or negative
958 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
959
reed4af35f32014-06-27 17:47:49 -0700960 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700961 const bool completeOverwrite = info.dimensions() == size;
962 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700963
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000964 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000965 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000966}
reed@google.com51df9e32010-12-23 19:29:18 +0000967
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968//////////////////////////////////////////////////////////////////////////////
969
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970void SkCanvas::updateDeviceCMCache() {
971 if (fDeviceCMDirty) {
972 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700973 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000975
halcanary96fcdcc2015-08-27 07:41:13 -0700976 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700977 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000979 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980 do {
reedde6c5312016-09-02 12:10:07 -0700981 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700982 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000983 }
984 fDeviceCMDirty = false;
985 }
986}
987
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988///////////////////////////////////////////////////////////////////////////////
989
reed2ff1fce2014-12-11 07:07:37 -0800990void SkCanvas::checkForDeferredSave() {
991 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800992 this->doSave();
993 }
994}
995
reedf0090cb2014-11-26 08:55:51 -0800996int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800997#ifdef SK_DEBUG
998 int count = 0;
999 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1000 for (;;) {
1001 const MCRec* rec = (const MCRec*)iter.next();
1002 if (!rec) {
1003 break;
1004 }
1005 count += 1 + rec->fDeferredSaveCount;
1006 }
1007 SkASSERT(count == fSaveCount);
1008#endif
1009 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001010}
1011
1012int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001013 fSaveCount += 1;
1014 fMCRec->fDeferredSaveCount += 1;
1015 return this->getSaveCount() - 1; // return our prev value
1016}
1017
1018void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001019 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001020
1021 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1022 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001023 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001024}
1025
1026void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001027 if (fMCRec->fDeferredSaveCount > 0) {
1028 SkASSERT(fSaveCount > 1);
1029 fSaveCount -= 1;
1030 fMCRec->fDeferredSaveCount -= 1;
1031 } else {
1032 // check for underflow
1033 if (fMCStack.count() > 1) {
1034 this->willRestore();
1035 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001036 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001037 this->internalRestore();
1038 this->didRestore();
1039 }
reedf0090cb2014-11-26 08:55:51 -08001040 }
1041}
1042
1043void SkCanvas::restoreToCount(int count) {
1044 // sanity check
1045 if (count < 1) {
1046 count = 1;
1047 }
mtkleinf0f14112014-12-12 08:46:25 -08001048
reedf0090cb2014-11-26 08:55:51 -08001049 int n = this->getSaveCount() - count;
1050 for (int i = 0; i < n; ++i) {
1051 this->restore();
1052 }
1053}
1054
reed2ff1fce2014-12-11 07:07:37 -08001055void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001057 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001059
reed687fa1c2015-04-07 08:00:56 -07001060 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001061}
1062
reed4960eee2015-12-18 07:09:18 -08001063bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001064 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001065}
1066
reed4960eee2015-12-18 07:09:18 -08001067bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001068 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001069 SkIRect clipBounds;
1070 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001071 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001072 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001073
reed96e657d2015-03-10 17:30:07 -07001074 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1075
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001076 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001077 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001078 if (bounds && !imageFilter->canComputeFastBounds()) {
1079 bounds = nullptr;
1080 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001081 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001082 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001083 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001085
reed96e657d2015-03-10 17:30:07 -07001086 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 r.roundOut(&ir);
1088 // early exit if the layer's bounds are clipped out
1089 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001090 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001091 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001092 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001093 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001094 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095 }
1096 } else { // no user bounds, so just use the clip
1097 ir = clipBounds;
1098 }
reed180aec42015-03-11 10:39:04 -07001099 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100
reed4960eee2015-12-18 07:09:18 -08001101 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001102 // Simplify the current clips since they will be applied properly during restore()
reed73603f32016-09-20 08:42:38 -07001103 fClipStack->clipDevRect(ir, kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001104 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001105 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001106 }
1107
1108 if (intersection) {
1109 *intersection = ir;
1110 }
1111 return true;
1112}
1113
reed4960eee2015-12-18 07:09:18 -08001114
reed4960eee2015-12-18 07:09:18 -08001115int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1116 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001117}
1118
reed70ee31b2015-12-10 13:44:45 -08001119int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001120 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1121}
1122
1123int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1124 SaveLayerRec rec(origRec);
1125 if (gIgnoreSaveLayerBounds) {
1126 rec.fBounds = nullptr;
1127 }
1128 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1129 fSaveCount += 1;
1130 this->internalSaveLayer(rec, strategy);
1131 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001132}
1133
reeda2217ef2016-07-20 06:04:34 -07001134void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1135 SkBaseDevice* dst, const SkMatrix& ctm,
1136 const SkClipStack* clipStack) {
1137 SkDraw draw;
1138 SkRasterClip rc;
1139 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1140 if (!dst->accessPixels(&draw.fDst)) {
1141 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001142 }
reeda2217ef2016-07-20 06:04:34 -07001143 draw.fMatrix = &SkMatrix::I();
1144 draw.fRC = &rc;
1145 draw.fClipStack = clipStack;
1146 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001147
1148 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001149 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001150
1151 int x = src->getOrigin().x() - dst->getOrigin().x();
1152 int y = src->getOrigin().y() - dst->getOrigin().y();
1153 auto special = src->snapSpecial();
1154 if (special) {
1155 dst->drawSpecial(draw, special.get(), x, y, p);
1156 }
robertphillips7354a4b2015-12-16 05:08:27 -08001157}
reed70ee31b2015-12-10 13:44:45 -08001158
reed129ed1c2016-02-22 06:42:31 -08001159static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1160 const SkPaint* paint) {
1161 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1162 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001163 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001164 const bool hasImageFilter = paint && paint->getImageFilter();
1165
1166 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1167 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1168 // force to L32
1169 return SkImageInfo::MakeN32(w, h, alphaType);
1170 } else {
1171 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001172 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001173 }
1174}
1175
reed4960eee2015-12-18 07:09:18 -08001176void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1177 const SkRect* bounds = rec.fBounds;
1178 const SkPaint* paint = rec.fPaint;
1179 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1180
reed8c30a812016-04-20 16:36:51 -07001181 SkLazyPaint lazyP;
1182 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1183 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001184 SkMatrix remainder;
1185 SkSize scale;
1186 /*
1187 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1188 * but they do handle scaling. To accommodate this, we do the following:
1189 *
1190 * 1. Stash off the current CTM
1191 * 2. Decompose the CTM into SCALE and REMAINDER
1192 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1193 * contains the REMAINDER
1194 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1195 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1196 * of the original imagefilter, and draw that (via drawSprite)
1197 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1198 *
1199 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1200 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1201 */
reed96a04f32016-04-25 09:25:15 -07001202 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001203 stashedMatrix.decomposeScale(&scale, &remainder))
1204 {
1205 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1206 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1207 SkPaint* p = lazyP.set(*paint);
1208 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1209 SkFilterQuality::kLow_SkFilterQuality,
1210 sk_ref_sp(imageFilter)));
1211 imageFilter = p->getImageFilter();
1212 paint = p;
1213 }
reed8c30a812016-04-20 16:36:51 -07001214
junov@chromium.orga907ac32012-02-24 21:54:07 +00001215 // do this before we create the layer. We don't call the public save() since
1216 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001217 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001218
1219 fDeviceCMDirty = true;
1220
1221 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001222 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001223 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224 }
1225
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001226 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1227 // the clipRectBounds() call above?
1228 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001229 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001230 }
1231
reed4960eee2015-12-18 07:09:18 -08001232 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001233 SkPixelGeometry geo = fProps.pixelGeometry();
1234 if (paint) {
reed76033be2015-03-14 10:54:31 -07001235 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001236 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001237 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001238 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001239 }
1240 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241
robertphillips5139e502016-07-19 05:10:40 -07001242 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001243 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001244 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001245 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001246 }
reedb2db8982014-11-13 12:41:02 -08001247
robertphillips5139e502016-07-19 05:10:40 -07001248 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001249 paint);
1250
robertphillips5139e502016-07-19 05:10:40 -07001251 SkAutoTUnref<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001252 {
reed70ee31b2015-12-10 13:44:45 -08001253 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001254 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001255 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001256 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
reedcd4051e2016-07-15 09:41:26 -07001257 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001258 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1259 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001260 return;
reed61f501f2015-04-29 08:34:00 -07001261 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001262 }
robertphillips5139e502016-07-19 05:10:40 -07001263 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001264
robertphillips5139e502016-07-19 05:10:40 -07001265 DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266
1267 layer->fNext = fMCRec->fTopLayer;
1268 fMCRec->fLayer = layer;
1269 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001270
1271 if (rec.fBackdrop) {
1272 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice,
1273 fMCRec->fMatrix, this->getClipStack());
1274 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275}
1276
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001277int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001278 if (0xFF == alpha) {
1279 return this->saveLayer(bounds, nullptr);
1280 } else {
1281 SkPaint tmpPaint;
1282 tmpPaint.setAlpha(alpha);
1283 return this->saveLayer(bounds, &tmpPaint);
1284 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001285}
1286
reed@android.com8a1c16f2008-12-17 15:59:43 +00001287void SkCanvas::internalRestore() {
1288 SkASSERT(fMCStack.count() != 0);
1289
1290 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291
reed687fa1c2015-04-07 08:00:56 -07001292 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001293
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001294 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 DeviceCM* layer = fMCRec->fLayer; // may be null
1296 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001297 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298
1299 // now do the normal restore()
1300 fMCRec->~MCRec(); // balanced in save()
1301 fMCStack.pop_back();
1302 fMCRec = (MCRec*)fMCStack.back();
1303
1304 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1305 since if we're being recorded, we don't want to record this (the
1306 recorder will have already recorded the restore).
1307 */
bsalomon49f085d2014-09-05 13:34:00 -07001308 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001310 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001311 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001312 // restore what we smashed in internalSaveLayer
1313 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001314 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001316 delete layer;
reedb679ca82015-04-07 04:40:48 -07001317 } else {
1318 // we're at the root
reeda499f902015-05-01 09:34:31 -07001319 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001320 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001321 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001323 }
msarettfbfa2582016-08-12 08:29:08 -07001324
1325 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001326 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001327 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001329}
1330
reede8f30622016-03-23 18:59:25 -07001331sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001332 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001333 props = &fProps;
1334 }
1335 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001336}
1337
reede8f30622016-03-23 18:59:25 -07001338sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001339 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001340 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001341}
1342
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001343SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001344 return this->onImageInfo();
1345}
1346
1347SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001348 SkBaseDevice* dev = this->getDevice();
1349 if (dev) {
1350 return dev->imageInfo();
1351 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001352 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001353 }
1354}
1355
brianosman898235c2016-04-06 07:38:23 -07001356bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001357 return this->onGetProps(props);
1358}
1359
1360bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001361 SkBaseDevice* dev = this->getDevice();
1362 if (dev) {
1363 if (props) {
1364 *props = fProps;
1365 }
1366 return true;
1367 } else {
1368 return false;
1369 }
1370}
1371
reed6ceeebd2016-03-09 14:26:26 -08001372#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001373const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001374 SkPixmap pmap;
reed6ceeebd2016-03-09 14:26:26 -08001375 if (this->peekPixels(&pmap)) {
1376 if (info) {
1377 *info = pmap.info();
1378 }
1379 if (rowBytes) {
1380 *rowBytes = pmap.rowBytes();
1381 }
1382 return pmap.addr();
reed884e97c2015-05-26 11:31:54 -07001383 }
reed6ceeebd2016-03-09 14:26:26 -08001384 return nullptr;
1385}
1386#endif
1387
1388bool SkCanvas::peekPixels(SkPixmap* pmap) {
1389 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001390}
1391
reed884e97c2015-05-26 11:31:54 -07001392bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001393 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001394 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001395}
1396
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001397void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001398 SkPixmap pmap;
1399 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001400 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001401 }
1402 if (info) {
1403 *info = pmap.info();
1404 }
1405 if (rowBytes) {
1406 *rowBytes = pmap.rowBytes();
1407 }
1408 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001409 *origin = this->getTopDevice(false)->getOrigin();
1410 }
reed884e97c2015-05-26 11:31:54 -07001411 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001412}
1413
reed884e97c2015-05-26 11:31:54 -07001414bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001415 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001416 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001417}
1418
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420
reed7503d602016-07-15 14:23:29 -07001421void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001423 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424 paint = &tmp;
1425 }
reed@google.com4b226022011-01-11 18:32:13 +00001426
reed@google.com8926b162012-03-23 15:36:36 +00001427 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001428
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001430 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001431 paint = &looper.paint();
1432 SkImageFilter* filter = paint->getImageFilter();
1433 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
senorblancof35566e2016-04-18 10:32:02 -07001434 if (filter) {
reeda2217ef2016-07-20 06:04:34 -07001435 dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001436 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001437 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001438 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439 }
reeda2217ef2016-07-20 06:04:34 -07001440
reed@google.com4e2b3d32011-04-07 14:18:59 +00001441 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442}
1443
reed32704672015-12-16 08:27:10 -08001444/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001445
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001446void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001447 if (dx || dy) {
1448 this->checkForDeferredSave();
1449 fDeviceCMDirty = true;
1450 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001451
reedfe69b502016-09-12 06:31:48 -07001452 // Translate shouldn't affect the is-scale-translateness of the matrix.
1453 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001454
reedfe69b502016-09-12 06:31:48 -07001455 this->didTranslate(dx,dy);
1456 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001457}
1458
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001459void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001460 SkMatrix m;
1461 m.setScale(sx, sy);
1462 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001463}
1464
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001465void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001466 SkMatrix m;
1467 m.setRotate(degrees);
1468 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001469}
1470
bungeman7438bfc2016-07-12 15:01:19 -07001471void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1472 SkMatrix m;
1473 m.setRotate(degrees, px, py);
1474 this->concat(m);
1475}
1476
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001477void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001478 SkMatrix m;
1479 m.setSkew(sx, sy);
1480 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001481}
1482
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001483void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001484 if (matrix.isIdentity()) {
1485 return;
1486 }
1487
reed2ff1fce2014-12-11 07:07:37 -08001488 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001489 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001490 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001491 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001492 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001493}
1494
reed8c30a812016-04-20 16:36:51 -07001495void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001496 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001497 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001498 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001499}
1500
1501void SkCanvas::setMatrix(const SkMatrix& matrix) {
1502 this->checkForDeferredSave();
1503 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001504 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505}
1506
reed@android.com8a1c16f2008-12-17 15:59:43 +00001507void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001508 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001509}
1510
vjiaoblack95302da2016-07-21 10:25:54 -07001511#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001512void SkCanvas::translateZ(SkScalar z) {
1513 this->checkForDeferredSave();
1514 this->fMCRec->fCurDrawDepth += z;
1515 this->didTranslateZ(z);
1516}
1517
1518SkScalar SkCanvas::getZ() const {
1519 return this->fMCRec->fCurDrawDepth;
1520}
1521
vjiaoblack95302da2016-07-21 10:25:54 -07001522void SkCanvas::setLights(sk_sp<SkLights> lights) {
1523 this->fLights = lights;
1524}
1525
1526sk_sp<SkLights> SkCanvas::getLights() const {
1527 return this->fLights;
1528}
1529#endif
1530
reed@android.com8a1c16f2008-12-17 15:59:43 +00001531//////////////////////////////////////////////////////////////////////////////
1532
reed73603f32016-09-20 08:42:38 -07001533void SkCanvas::clipRect(const SkRect& rect, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001534 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001535 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1536 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001537}
1538
reed73603f32016-09-20 08:42:38 -07001539void SkCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001540 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reedc64eff52015-11-21 12:39:45 -08001541 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001542 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1543 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1544 isAA);
reedc64eff52015-11-21 12:39:45 -08001545 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001546 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001547}
1548
reed73603f32016-09-20 08:42:38 -07001549void SkCanvas::clipRRect(const SkRRect& rrect, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001550 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001551 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001552 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001553 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1554 } else {
1555 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001556 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001557}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001558
reed73603f32016-09-20 08:42:38 -07001559void SkCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001560 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001561
Brian Salomona3b45d42016-10-03 11:36:16 -04001562 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001563
Brian Salomona3b45d42016-10-03 11:36:16 -04001564 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1565 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1566 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1567 isAA);
1568 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1569 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001570}
1571
reed73603f32016-09-20 08:42:38 -07001572void SkCanvas::clipPath(const SkPath& path, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001573 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001574 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001575
1576 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1577 SkRect r;
1578 if (path.isRect(&r)) {
1579 this->onClipRect(r, op, edgeStyle);
1580 return;
1581 }
1582 SkRRect rrect;
1583 if (path.isOval(&r)) {
1584 rrect.setOval(r);
1585 this->onClipRRect(rrect, op, edgeStyle);
1586 return;
1587 }
1588 if (path.isRRect(&rrect)) {
1589 this->onClipRRect(rrect, op, edgeStyle);
1590 return;
1591 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001592 }
robertphillips39f05382015-11-24 09:30:12 -08001593
1594 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001595}
1596
reed73603f32016-09-20 08:42:38 -07001597void SkCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001598 AutoValidateClip avc(this);
1599
reed@android.com8a1c16f2008-12-17 15:59:43 +00001600 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001601 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001602
Brian Salomona3b45d42016-10-03 11:36:16 -04001603 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001604
Brian Salomona3b45d42016-10-03 11:36:16 -04001605 const SkPath* rasterClipPath = &path;
1606 const SkMatrix* matrix = &fMCRec->fMatrix;
1607 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001608 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001609 isAA = getClipStack()->asPath(&tempPath);
1610 rasterClipPath = &tempPath;
1611 matrix = &SkMatrix::I();
reed73603f32016-09-20 08:42:38 -07001612 op = kReplace_Op;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001613 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001614 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1615 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001616 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001617}
1618
reed73603f32016-09-20 08:42:38 -07001619void SkCanvas::clipRegion(const SkRegion& rgn, ClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001620 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001621 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001622}
1623
reed73603f32016-09-20 08:42:38 -07001624void SkCanvas::onClipRegion(const SkRegion& rgn, ClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001625 AutoValidateClip avc(this);
1626
reed@android.com8a1c16f2008-12-17 15:59:43 +00001627 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001628
reed@google.com5c3d1472011-02-22 19:12:23 +00001629 // todo: signal fClipStack that we have a region, and therefore (I guess)
1630 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001631 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001632
reed73603f32016-09-20 08:42:38 -07001633 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001634 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001635}
1636
reed@google.com819c9212011-02-23 18:56:55 +00001637#ifdef SK_DEBUG
1638void SkCanvas::validateClip() const {
1639 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001640 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001641 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001642 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001643 return;
1644 }
1645
reed@google.com819c9212011-02-23 18:56:55 +00001646 SkIRect ir;
1647 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001648 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001649
reed687fa1c2015-04-07 08:00:56 -07001650 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001651 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001652 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001653 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001654 case SkClipStack::Element::kRect_Type:
1655 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001656 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001657 break;
1658 case SkClipStack::Element::kEmpty_Type:
1659 tmpClip.setEmpty();
1660 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001661 default: {
1662 SkPath path;
1663 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001664 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1665 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001666 break;
1667 }
reed@google.com819c9212011-02-23 18:56:55 +00001668 }
1669 }
reed@google.com819c9212011-02-23 18:56:55 +00001670}
1671#endif
1672
reed@google.com90c07ea2012-04-13 13:50:27 +00001673void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001674 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001675 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001676
halcanary96fcdcc2015-08-27 07:41:13 -07001677 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001678 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001679 }
1680}
1681
reed@google.com5c3d1472011-02-22 19:12:23 +00001682///////////////////////////////////////////////////////////////////////////////
1683
reed@google.com754de5f2014-02-24 19:38:20 +00001684bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001685 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001686}
1687
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001688bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001689 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001690}
1691
msarettfbfa2582016-08-12 08:29:08 -07001692static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1693#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1694 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1695 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1696 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1697 return 0xF != _mm_movemask_ps(mask);
1698#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1699 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1700 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1701 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1702 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1703#else
1704 SkRect devRectAsRect;
1705 SkRect devClipAsRect;
1706 devRect.store(&devRectAsRect.fLeft);
1707 devClip.store(&devClipAsRect.fLeft);
1708 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1709#endif
1710}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001711
msarettfbfa2582016-08-12 08:29:08 -07001712// It's important for this function to not be inlined. Otherwise the compiler will share code
1713// between the fast path and the slow path, resulting in two slow paths.
1714static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1715 const SkMatrix& matrix) {
1716 SkRect deviceRect;
1717 matrix.mapRect(&deviceRect, src);
1718 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1719}
1720
1721bool SkCanvas::quickReject(const SkRect& src) const {
1722#ifdef SK_DEBUG
1723 // Verify that fDeviceClipBounds are set properly.
1724 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001725 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001726 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001727 } else {
msarettfbfa2582016-08-12 08:29:08 -07001728 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001729 }
msarettfbfa2582016-08-12 08:29:08 -07001730
msarett9637ea92016-08-18 14:03:30 -07001731 // Verify that fIsScaleTranslate is set properly.
1732 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001733#endif
1734
msarett9637ea92016-08-18 14:03:30 -07001735 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001736 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1737 }
1738
1739 // We inline the implementation of mapScaleTranslate() for the fast path.
1740 float sx = fMCRec->fMatrix.getScaleX();
1741 float sy = fMCRec->fMatrix.getScaleY();
1742 float tx = fMCRec->fMatrix.getTranslateX();
1743 float ty = fMCRec->fMatrix.getTranslateY();
1744 Sk4f scale(sx, sy, sx, sy);
1745 Sk4f trans(tx, ty, tx, ty);
1746
1747 // Apply matrix.
1748 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1749
1750 // Make sure left < right, top < bottom.
1751 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1752 Sk4f min = Sk4f::Min(ltrb, rblt);
1753 Sk4f max = Sk4f::Max(ltrb, rblt);
1754 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1755 // ARM this sequence generates the fastest (a single instruction).
1756 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1757
1758 // Check if the device rect is NaN or outside the clip.
1759 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001760}
1761
reed@google.com3b3e8952012-08-16 20:53:31 +00001762bool SkCanvas::quickReject(const SkPath& path) const {
1763 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001764}
1765
reed@google.com3b3e8952012-08-16 20:53:31 +00001766bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001767 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001768 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001769 return false;
1770 }
1771
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001772 SkMatrix inverse;
1773 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001774 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001775 if (bounds) {
1776 bounds->setEmpty();
1777 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001778 return false;
1779 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001780
bsalomon49f085d2014-09-05 13:34:00 -07001781 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001782 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001783 // adjust it outwards in case we are antialiasing
1784 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001785
reed@google.com8f4d2302013-12-17 16:44:46 +00001786 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1787 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001788 inverse.mapRect(bounds, r);
1789 }
1790 return true;
1791}
1792
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001793bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001794 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001795 if (clip.isEmpty()) {
1796 if (bounds) {
1797 bounds->setEmpty();
1798 }
1799 return false;
1800 }
1801
bsalomon49f085d2014-09-05 13:34:00 -07001802 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001803 *bounds = clip.getBounds();
1804 }
1805 return true;
1806}
1807
reed@android.com8a1c16f2008-12-17 15:59:43 +00001808const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001809 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001810}
1811
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001812const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001813 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001814}
1815
Brian Osman11052242016-10-27 14:47:55 -04001816GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001817 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001818 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001819}
1820
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001821GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001822 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001823 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001824}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001825
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001826void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1827 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001828 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001829 if (outer.isEmpty()) {
1830 return;
1831 }
1832 if (inner.isEmpty()) {
1833 this->drawRRect(outer, paint);
1834 return;
1835 }
1836
1837 // We don't have this method (yet), but technically this is what we should
1838 // be able to assert...
1839 // SkASSERT(outer.contains(inner));
1840 //
1841 // For now at least check for containment of bounds
1842 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1843
1844 this->onDrawDRRect(outer, inner, paint);
1845}
1846
reed41af9662015-01-05 07:49:08 -08001847// These need to stop being virtual -- clients need to override the onDraw... versions
1848
1849void SkCanvas::drawPaint(const SkPaint& paint) {
1850 this->onDrawPaint(paint);
1851}
1852
1853void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1854 this->onDrawRect(r, paint);
1855}
1856
msarettdca352e2016-08-26 06:37:45 -07001857void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1858 if (region.isEmpty()) {
1859 return;
1860 }
1861
1862 if (region.isRect()) {
1863 return this->drawIRect(region.getBounds(), paint);
1864 }
1865
1866 this->onDrawRegion(region, paint);
1867}
1868
reed41af9662015-01-05 07:49:08 -08001869void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1870 this->onDrawOval(r, paint);
1871}
1872
1873void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1874 this->onDrawRRect(rrect, paint);
1875}
1876
1877void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1878 this->onDrawPoints(mode, count, pts, paint);
1879}
1880
1881void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001882 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001883 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reed7d954ad2016-10-28 15:42:34 -04001884#ifdef SK_SUPPORT_LEGACY_XFERMODE_PARAM
1885 SkXfermode* xmode = SkXfermode::Peek(bmode);
1886#else
1887 SkBlendMode xmode = bmode;
1888#endif
reed41af9662015-01-05 07:49:08 -08001889 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1890 indices, indexCount, paint);
1891}
1892
1893void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1894 this->onDrawPath(path, paint);
1895}
1896
reeda85d4d02015-05-06 12:56:48 -07001897void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001898 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001899 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001900}
1901
reede47829b2015-08-06 10:02:53 -07001902void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1903 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001904 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001905 if (dst.isEmpty() || src.isEmpty()) {
1906 return;
1907 }
1908 this->onDrawImageRect(image, &src, dst, paint, constraint);
1909}
reed41af9662015-01-05 07:49:08 -08001910
reed84984ef2015-07-17 07:09:43 -07001911void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1912 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001913 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001914 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001915}
1916
reede47829b2015-08-06 10:02:53 -07001917void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1918 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001919 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001920 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1921 constraint);
1922}
reede47829b2015-08-06 10:02:53 -07001923
reed4c21dc52015-06-25 12:32:03 -07001924void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1925 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001926 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001927 if (dst.isEmpty()) {
1928 return;
1929 }
msarett552bca92016-08-03 06:53:26 -07001930 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1931 this->onDrawImageNine(image, center, dst, paint);
1932 } else {
reede47829b2015-08-06 10:02:53 -07001933 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001934 }
reed4c21dc52015-06-25 12:32:03 -07001935}
1936
msarett16882062016-08-16 09:31:08 -07001937void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1938 const SkPaint* paint) {
1939 RETURN_ON_NULL(image);
1940 if (dst.isEmpty()) {
1941 return;
1942 }
msarett71df2d72016-09-30 12:41:42 -07001943
1944 SkIRect bounds;
1945 Lattice latticePlusBounds = lattice;
1946 if (!latticePlusBounds.fBounds) {
1947 bounds = SkIRect::MakeWH(image->width(), image->height());
1948 latticePlusBounds.fBounds = &bounds;
1949 }
1950
1951 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1952 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001953 } else {
1954 this->drawImageRect(image, dst, paint);
1955 }
1956}
1957
reed41af9662015-01-05 07:49:08 -08001958void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001959 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001960 return;
1961 }
reed41af9662015-01-05 07:49:08 -08001962 this->onDrawBitmap(bitmap, dx, dy, paint);
1963}
1964
reede47829b2015-08-06 10:02:53 -07001965void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001966 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001967 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001968 return;
1969 }
reede47829b2015-08-06 10:02:53 -07001970 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001971}
1972
reed84984ef2015-07-17 07:09:43 -07001973void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1974 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001975 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001976}
1977
reede47829b2015-08-06 10:02:53 -07001978void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1979 SrcRectConstraint constraint) {
1980 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1981 constraint);
1982}
reede47829b2015-08-06 10:02:53 -07001983
reed41af9662015-01-05 07:49:08 -08001984void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1985 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001986 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001987 return;
1988 }
msarett552bca92016-08-03 06:53:26 -07001989 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1990 this->onDrawBitmapNine(bitmap, center, dst, paint);
1991 } else {
reeda5517e22015-07-14 10:54:12 -07001992 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001993 }
reed41af9662015-01-05 07:49:08 -08001994}
1995
msarettc573a402016-08-02 08:05:56 -07001996void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1997 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001998 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001999 return;
2000 }
msarett71df2d72016-09-30 12:41:42 -07002001
2002 SkIRect bounds;
2003 Lattice latticePlusBounds = lattice;
2004 if (!latticePlusBounds.fBounds) {
2005 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2006 latticePlusBounds.fBounds = &bounds;
2007 }
2008
2009 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2010 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002011 } else {
msarett16882062016-08-16 09:31:08 -07002012 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002013 }
msarettc573a402016-08-02 08:05:56 -07002014}
2015
reed71c3c762015-06-24 10:29:17 -07002016void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002017 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002018 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002019 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002020 if (count <= 0) {
2021 return;
2022 }
2023 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002024 SkASSERT(tex);
Mike Reed7d954ad2016-10-28 15:42:34 -04002025 this->onDrawAtlas(atlas, xform, tex, colors, count, (SK_XFERMODE_MODE_PARAM)mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002026}
2027
reedf70b5312016-03-04 16:36:20 -08002028void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2029 if (key) {
2030 this->onDrawAnnotation(rect, key, value);
2031 }
2032}
2033
reede47829b2015-08-06 10:02:53 -07002034void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2035 const SkPaint* paint, SrcRectConstraint constraint) {
2036 if (src) {
2037 this->drawImageRect(image, *src, dst, paint, constraint);
2038 } else {
2039 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2040 dst, paint, constraint);
2041 }
2042}
2043void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2044 const SkPaint* paint, SrcRectConstraint constraint) {
2045 if (src) {
2046 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2047 } else {
2048 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2049 dst, paint, constraint);
2050 }
2051}
2052
tomhudsoncb3bd182016-05-18 07:24:16 -07002053void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2054 SkIRect layer_bounds = this->getTopLayerBounds();
2055 if (matrix) {
2056 *matrix = this->getTotalMatrix();
2057 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2058 }
2059 if (clip_bounds) {
2060 this->getClipDeviceBounds(clip_bounds);
2061 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2062 }
2063}
2064
reed@android.com8a1c16f2008-12-17 15:59:43 +00002065//////////////////////////////////////////////////////////////////////////////
2066// These are the virtual drawing methods
2067//////////////////////////////////////////////////////////////////////////////
2068
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002069void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002070 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002071 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2072 }
2073}
2074
reed41af9662015-01-05 07:49:08 -08002075void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002076 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002077 this->internalDrawPaint(paint);
2078}
2079
2080void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002081 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082
2083 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002084 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002085 }
2086
reed@google.com4e2b3d32011-04-07 14:18:59 +00002087 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002088}
2089
reed41af9662015-01-05 07:49:08 -08002090void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2091 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002092 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093 if ((long)count <= 0) {
2094 return;
2095 }
2096
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002097 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002098 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002099 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002100 // special-case 2 points (common for drawing a single line)
2101 if (2 == count) {
2102 r.set(pts[0], pts[1]);
2103 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002104 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002105 }
senorblanco87e066e2015-10-28 11:23:36 -07002106 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2107 return;
2108 }
2109 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002110 }
reed@google.coma584aed2012-05-16 14:06:02 +00002111
halcanary96fcdcc2015-08-27 07:41:13 -07002112 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002113
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002114 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002115
reed@android.com8a1c16f2008-12-17 15:59:43 +00002116 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002117 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002118 }
reed@google.com4b226022011-01-11 18:32:13 +00002119
reed@google.com4e2b3d32011-04-07 14:18:59 +00002120 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002121}
2122
reed4a167172016-08-18 17:15:25 -07002123static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2124 return ((intptr_t)paint.getImageFilter() |
2125#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2126 (intptr_t)canvas->getDrawFilter() |
2127#endif
2128 (intptr_t)paint.getLooper() ) != 0;
2129}
2130
reed41af9662015-01-05 07:49:08 -08002131void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002132 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002133 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002134 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002135 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002136 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2137 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2138 SkRect tmp(r);
2139 tmp.sort();
2140
senorblanco87e066e2015-10-28 11:23:36 -07002141 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2142 return;
2143 }
2144 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145 }
reed@google.com4b226022011-01-11 18:32:13 +00002146
reed4a167172016-08-18 17:15:25 -07002147 if (needs_autodrawlooper(this, paint)) {
2148 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002149
reed4a167172016-08-18 17:15:25 -07002150 while (iter.next()) {
2151 iter.fDevice->drawRect(iter, r, looper.paint());
2152 }
2153
2154 LOOPER_END
2155 } else {
2156 this->predrawNotify(bounds, &paint, false);
2157 SkDrawIter iter(this);
2158 while (iter.next()) {
2159 iter.fDevice->drawRect(iter, r, paint);
2160 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002161 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002162}
2163
msarett44df6512016-08-25 13:54:30 -07002164void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2165 SkRect storage;
2166 SkRect regionRect = SkRect::Make(region.getBounds());
2167 const SkRect* bounds = nullptr;
2168 if (paint.canComputeFastBounds()) {
2169 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2170 return;
2171 }
2172 bounds = &regionRect;
2173 }
2174
2175 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2176
2177 while (iter.next()) {
2178 iter.fDevice->drawRegion(iter, region, looper.paint());
2179 }
2180
2181 LOOPER_END
2182}
2183
reed41af9662015-01-05 07:49:08 -08002184void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002185 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002186 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002187 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002188 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002189 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2190 return;
2191 }
2192 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002193 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002194
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002195 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002196
2197 while (iter.next()) {
2198 iter.fDevice->drawOval(iter, oval, looper.paint());
2199 }
2200
2201 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002202}
2203
bsalomonac3aa242016-08-19 11:25:19 -07002204void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2205 SkScalar sweepAngle, bool useCenter,
2206 const SkPaint& paint) {
2207 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2208 const SkRect* bounds = nullptr;
2209 if (paint.canComputeFastBounds()) {
2210 SkRect storage;
2211 // Note we're using the entire oval as the bounds.
2212 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2213 return;
2214 }
2215 bounds = &oval;
2216 }
2217
2218 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2219
2220 while (iter.next()) {
2221 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2222 }
2223
2224 LOOPER_END
2225}
2226
reed41af9662015-01-05 07:49:08 -08002227void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002228 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002229 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002230 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002231 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002232 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2233 return;
2234 }
2235 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002236 }
2237
2238 if (rrect.isRect()) {
2239 // call the non-virtual version
2240 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002241 return;
2242 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002243 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002244 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2245 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002246 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002247
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002248 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002249
2250 while (iter.next()) {
2251 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2252 }
2253
2254 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002255}
2256
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002257void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2258 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002259 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002260 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002261 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002262 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2263 return;
2264 }
2265 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002266 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002267
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002268 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002269
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002270 while (iter.next()) {
2271 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2272 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002273
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002274 LOOPER_END
2275}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002276
reed41af9662015-01-05 07:49:08 -08002277void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002278 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002279 if (!path.isFinite()) {
2280 return;
2281 }
2282
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002283 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002284 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002285 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002286 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002287 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2288 return;
2289 }
2290 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002291 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002292
2293 const SkRect& r = path.getBounds();
2294 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002295 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002296 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002297 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002298 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002299 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002300
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002301 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302
2303 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002304 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305 }
2306
reed@google.com4e2b3d32011-04-07 14:18:59 +00002307 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308}
2309
reed262a71b2015-12-05 13:07:27 -08002310bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002311 if (!paint.getImageFilter()) {
2312 return false;
2313 }
2314
2315 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002316 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002317 return false;
2318 }
2319
2320 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2321 // Once we can filter and the filter will return a result larger than itself, we should be
2322 // able to remove this constraint.
2323 // skbug.com/4526
2324 //
2325 SkPoint pt;
2326 ctm.mapXY(x, y, &pt);
2327 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2328 return ir.contains(fMCRec->fRasterClip.getBounds());
2329}
2330
reeda85d4d02015-05-06 12:56:48 -07002331void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002332 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002333 SkRect bounds = SkRect::MakeXYWH(x, y,
2334 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002335 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002336 SkRect tmp = bounds;
2337 if (paint) {
2338 paint->computeFastBounds(tmp, &tmp);
2339 }
2340 if (this->quickReject(tmp)) {
2341 return;
2342 }
reeda85d4d02015-05-06 12:56:48 -07002343 }
halcanary9d524f22016-03-29 09:03:52 -07002344
reeda85d4d02015-05-06 12:56:48 -07002345 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002346 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002347 paint = lazy.init();
2348 }
reed262a71b2015-12-05 13:07:27 -08002349
reeda2217ef2016-07-20 06:04:34 -07002350 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002351 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2352 *paint);
2353 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002354 special = this->getDevice()->makeSpecial(image);
2355 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002356 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002357 }
2358 }
2359
reed262a71b2015-12-05 13:07:27 -08002360 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2361
reeda85d4d02015-05-06 12:56:48 -07002362 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002363 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002364 if (special) {
2365 SkPoint pt;
2366 iter.fMatrix->mapXY(x, y, &pt);
2367 iter.fDevice->drawSpecial(iter, special.get(),
2368 SkScalarRoundToInt(pt.fX),
2369 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002370 } else {
2371 iter.fDevice->drawImage(iter, image, x, y, pnt);
2372 }
reeda85d4d02015-05-06 12:56:48 -07002373 }
halcanary9d524f22016-03-29 09:03:52 -07002374
reeda85d4d02015-05-06 12:56:48 -07002375 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002376}
2377
reed41af9662015-01-05 07:49:08 -08002378void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002379 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002380 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002381 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002382 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002383 if (paint) {
2384 paint->computeFastBounds(dst, &storage);
2385 }
2386 if (this->quickReject(storage)) {
2387 return;
2388 }
reeda85d4d02015-05-06 12:56:48 -07002389 }
2390 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002391 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002392 paint = lazy.init();
2393 }
halcanary9d524f22016-03-29 09:03:52 -07002394
senorblancoc41e7e12015-12-07 12:51:30 -08002395 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002396 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002397
reeda85d4d02015-05-06 12:56:48 -07002398 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002399 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002400 }
halcanary9d524f22016-03-29 09:03:52 -07002401
reeda85d4d02015-05-06 12:56:48 -07002402 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002403}
2404
reed41af9662015-01-05 07:49:08 -08002405void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002406 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002407 SkDEBUGCODE(bitmap.validate();)
2408
reed33366972015-10-08 09:22:02 -07002409 if (bitmap.drawsNothing()) {
2410 return;
2411 }
2412
2413 SkLazyPaint lazy;
2414 if (nullptr == paint) {
2415 paint = lazy.init();
2416 }
2417
2418 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2419
2420 SkRect storage;
2421 const SkRect* bounds = nullptr;
2422 if (paint->canComputeFastBounds()) {
2423 bitmap.getBounds(&storage);
2424 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002425 SkRect tmp = storage;
2426 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2427 return;
2428 }
2429 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002430 }
reed@google.com4b226022011-01-11 18:32:13 +00002431
reeda2217ef2016-07-20 06:04:34 -07002432 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002433 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2434 *paint);
2435 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002436 special = this->getDevice()->makeSpecial(bitmap);
2437 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002438 drawAsSprite = false;
2439 }
2440 }
2441
reed262a71b2015-12-05 13:07:27 -08002442 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002443
2444 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002445 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002446 if (special) {
reed262a71b2015-12-05 13:07:27 -08002447 SkPoint pt;
2448 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002449 iter.fDevice->drawSpecial(iter, special.get(),
2450 SkScalarRoundToInt(pt.fX),
2451 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002452 } else {
2453 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2454 }
reed33366972015-10-08 09:22:02 -07002455 }
msarettfbfa2582016-08-12 08:29:08 -07002456
reed33366972015-10-08 09:22:02 -07002457 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002458}
2459
reed@google.com9987ec32011-09-07 11:57:52 +00002460// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002461void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002462 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002463 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002464 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465 return;
2466 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002467
halcanary96fcdcc2015-08-27 07:41:13 -07002468 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002469 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002470 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2471 return;
2472 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473 }
reed@google.com3d608122011-11-21 15:16:16 +00002474
reed@google.com33535f32012-09-25 15:37:50 +00002475 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002476 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002477 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002479
senorblancoc41e7e12015-12-07 12:51:30 -08002480 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002481 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002482
reed@google.com33535f32012-09-25 15:37:50 +00002483 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002484 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002485 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002486
reed@google.com33535f32012-09-25 15:37:50 +00002487 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488}
2489
reed41af9662015-01-05 07:49:08 -08002490void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002491 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002492 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002493 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002494 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002495}
2496
reed4c21dc52015-06-25 12:32:03 -07002497void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2498 const SkPaint* paint) {
2499 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002500
halcanary96fcdcc2015-08-27 07:41:13 -07002501 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002502 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002503 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2504 return;
2505 }
reed@google.com3d608122011-11-21 15:16:16 +00002506 }
halcanary9d524f22016-03-29 09:03:52 -07002507
reed4c21dc52015-06-25 12:32:03 -07002508 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002509 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002510 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002511 }
halcanary9d524f22016-03-29 09:03:52 -07002512
senorblancoc41e7e12015-12-07 12:51:30 -08002513 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002514
reed4c21dc52015-06-25 12:32:03 -07002515 while (iter.next()) {
2516 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002517 }
halcanary9d524f22016-03-29 09:03:52 -07002518
reed4c21dc52015-06-25 12:32:03 -07002519 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002520}
2521
reed41af9662015-01-05 07:49:08 -08002522void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2523 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002524 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002525 SkDEBUGCODE(bitmap.validate();)
2526
halcanary96fcdcc2015-08-27 07:41:13 -07002527 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002528 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002529 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2530 return;
2531 }
reed4c21dc52015-06-25 12:32:03 -07002532 }
halcanary9d524f22016-03-29 09:03:52 -07002533
reed4c21dc52015-06-25 12:32:03 -07002534 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002535 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002536 paint = lazy.init();
2537 }
halcanary9d524f22016-03-29 09:03:52 -07002538
senorblancoc41e7e12015-12-07 12:51:30 -08002539 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002540
reed4c21dc52015-06-25 12:32:03 -07002541 while (iter.next()) {
2542 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2543 }
halcanary9d524f22016-03-29 09:03:52 -07002544
reed4c21dc52015-06-25 12:32:03 -07002545 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002546}
2547
msarett16882062016-08-16 09:31:08 -07002548void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2549 const SkPaint* paint) {
2550 if (nullptr == paint || paint->canComputeFastBounds()) {
2551 SkRect storage;
2552 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2553 return;
2554 }
2555 }
2556
2557 SkLazyPaint lazy;
2558 if (nullptr == paint) {
2559 paint = lazy.init();
2560 }
2561
2562 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2563
2564 while (iter.next()) {
2565 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2566 }
2567
2568 LOOPER_END
2569}
2570
2571void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2572 const SkRect& dst, const SkPaint* paint) {
2573 if (nullptr == paint || paint->canComputeFastBounds()) {
2574 SkRect storage;
2575 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2576 return;
2577 }
2578 }
2579
2580 SkLazyPaint lazy;
2581 if (nullptr == paint) {
2582 paint = lazy.init();
2583 }
2584
2585 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2586
2587 while (iter.next()) {
2588 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2589 }
2590
2591 LOOPER_END
2592}
2593
reed@google.comf67e4cf2011-03-15 20:56:58 +00002594class SkDeviceFilteredPaint {
2595public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002596 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002597 uint32_t filteredFlags = device->filterTextFlags(paint);
2598 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002599 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002600 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002601 fPaint = newPaint;
2602 } else {
2603 fPaint = &paint;
2604 }
2605 }
2606
reed@google.comf67e4cf2011-03-15 20:56:58 +00002607 const SkPaint& paint() const { return *fPaint; }
2608
2609private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002610 const SkPaint* fPaint;
2611 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002612};
2613
bungeman@google.com52c748b2011-08-22 21:30:43 +00002614void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2615 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002616 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002617 draw.fDevice->drawRect(draw, r, paint);
2618 } else {
2619 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002620 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002621 draw.fDevice->drawRect(draw, r, p);
2622 }
2623}
2624
2625void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2626 const char text[], size_t byteLength,
2627 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002628 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002629
2630 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002631 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002632 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002633 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002634 return;
2635 }
2636
2637 SkScalar width = 0;
2638 SkPoint start;
2639
2640 start.set(0, 0); // to avoid warning
2641 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2642 SkPaint::kStrikeThruText_Flag)) {
2643 width = paint.measureText(text, byteLength);
2644
2645 SkScalar offsetX = 0;
2646 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2647 offsetX = SkScalarHalf(width);
2648 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2649 offsetX = width;
2650 }
2651 start.set(x - offsetX, y);
2652 }
2653
2654 if (0 == width) {
2655 return;
2656 }
2657
2658 uint32_t flags = paint.getFlags();
2659
2660 if (flags & (SkPaint::kUnderlineText_Flag |
2661 SkPaint::kStrikeThruText_Flag)) {
2662 SkScalar textSize = paint.getTextSize();
2663 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2664 SkRect r;
2665
2666 r.fLeft = start.fX;
2667 r.fRight = start.fX + width;
2668
2669 if (flags & SkPaint::kUnderlineText_Flag) {
2670 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2671 start.fY);
2672 r.fTop = offset;
2673 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002674 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002675 }
2676 if (flags & SkPaint::kStrikeThruText_Flag) {
2677 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2678 start.fY);
2679 r.fTop = offset;
2680 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002681 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002682 }
2683 }
2684}
2685
reed@google.come0d9ce82014-04-23 04:00:17 +00002686void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2687 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002688 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002689
2690 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002691 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002692 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002693 DrawTextDecorations(iter, dfp.paint(),
2694 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002695 }
2696
reed@google.com4e2b3d32011-04-07 14:18:59 +00002697 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698}
2699
reed@google.come0d9ce82014-04-23 04:00:17 +00002700void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2701 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002702 SkPoint textOffset = SkPoint::Make(0, 0);
2703
halcanary96fcdcc2015-08-27 07:41:13 -07002704 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002705
reed@android.com8a1c16f2008-12-17 15:59:43 +00002706 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002707 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002708 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002709 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002710 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002711
reed@google.com4e2b3d32011-04-07 14:18:59 +00002712 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002713}
2714
reed@google.come0d9ce82014-04-23 04:00:17 +00002715void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2716 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002717
2718 SkPoint textOffset = SkPoint::Make(0, constY);
2719
halcanary96fcdcc2015-08-27 07:41:13 -07002720 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002721
reed@android.com8a1c16f2008-12-17 15:59:43 +00002722 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002723 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002724 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002725 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002727
reed@google.com4e2b3d32011-04-07 14:18:59 +00002728 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002729}
2730
reed@google.come0d9ce82014-04-23 04:00:17 +00002731void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2732 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002733 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002734
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 while (iter.next()) {
2736 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002737 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002738 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002739
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002740 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002741}
2742
reed45561a02016-07-07 12:47:17 -07002743void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2744 const SkRect* cullRect, const SkPaint& paint) {
2745 if (cullRect && this->quickReject(*cullRect)) {
2746 return;
2747 }
2748
2749 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2750
2751 while (iter.next()) {
2752 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2753 }
2754
2755 LOOPER_END
2756}
2757
fmalita00d5c2c2014-08-21 08:53:26 -07002758void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2759 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002760
fmalita85d5eb92015-03-04 11:20:12 -08002761 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002762 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002763 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002764 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002765 SkRect tmp;
2766 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2767 return;
2768 }
2769 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002770 }
2771
fmalita024f9962015-03-03 19:08:17 -08002772 // We cannot filter in the looper as we normally do, because the paint is
2773 // incomplete at this point (text-related attributes are embedded within blob run paints).
2774 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002775 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002776
fmalita85d5eb92015-03-04 11:20:12 -08002777 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002778
fmalitaaa1b9122014-08-28 14:32:24 -07002779 while (iter.next()) {
2780 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002781 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002782 }
2783
fmalitaaa1b9122014-08-28 14:32:24 -07002784 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002785
2786 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002787}
2788
reed@google.come0d9ce82014-04-23 04:00:17 +00002789// These will become non-virtual, so they always call the (virtual) onDraw... method
2790void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2791 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002792 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002793 if (byteLength) {
2794 this->onDrawText(text, byteLength, x, y, paint);
2795 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002796}
2797void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2798 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002799 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002800 if (byteLength) {
2801 this->onDrawPosText(text, byteLength, pos, paint);
2802 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002803}
2804void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2805 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002806 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002807 if (byteLength) {
2808 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2809 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002810}
2811void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2812 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002813 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002814 if (byteLength) {
2815 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2816 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002817}
reed45561a02016-07-07 12:47:17 -07002818void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2819 const SkRect* cullRect, const SkPaint& paint) {
2820 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2821 if (byteLength) {
2822 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2823 }
2824}
fmalita00d5c2c2014-08-21 08:53:26 -07002825void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2826 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002827 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002828 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002829 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002830}
reed@google.come0d9ce82014-04-23 04:00:17 +00002831
reed41af9662015-01-05 07:49:08 -08002832void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2833 const SkPoint verts[], const SkPoint texs[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002834 const SkColor colors[], SK_XFERMODE_PARAM xmode,
reed41af9662015-01-05 07:49:08 -08002835 const uint16_t indices[], int indexCount,
2836 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002837 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002838 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002839
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840 while (iter.next()) {
2841 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002842 colors, xmode, indices, indexCount,
2843 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002844 }
reed@google.com4b226022011-01-11 18:32:13 +00002845
reed@google.com4e2b3d32011-04-07 14:18:59 +00002846 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847}
2848
dandovb3c9d1c2014-08-12 08:34:29 -07002849void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002850 const SkPoint texCoords[4], SkBlendMode bmode,
2851 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002852 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002853 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002854 return;
2855 }
mtklein6cfa73a2014-08-13 13:33:49 -07002856
Mike Reed7d954ad2016-10-28 15:42:34 -04002857#ifdef SK_SUPPORT_LEGACY_XFERMODE_PARAM
2858 SkXfermode* xmode = SkXfermode::Peek(bmode);
2859#else
2860 SkBlendMode xmode = bmode;
2861#endif
msarett9340c262016-09-22 05:20:21 -07002862 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2863}
2864
2865void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002866 const SkPoint texCoords[4], SK_XFERMODE_PARAM xmode,
2867 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002868 // Since a patch is always within the convex hull of the control points, we discard it when its
2869 // bounding rectangle is completely outside the current clip.
2870 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002871 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002872 if (this->quickReject(bounds)) {
2873 return;
2874 }
mtklein6cfa73a2014-08-13 13:33:49 -07002875
halcanary96fcdcc2015-08-27 07:41:13 -07002876 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002877
dandovecfff212014-08-04 10:02:00 -07002878 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002879 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002880 }
mtklein6cfa73a2014-08-13 13:33:49 -07002881
dandovecfff212014-08-04 10:02:00 -07002882 LOOPER_END
2883}
2884
reeda8db7282015-07-07 10:22:31 -07002885void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002886 RETURN_ON_NULL(dr);
2887 if (x || y) {
2888 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2889 this->onDrawDrawable(dr, &matrix);
2890 } else {
2891 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002892 }
2893}
2894
reeda8db7282015-07-07 10:22:31 -07002895void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002896 RETURN_ON_NULL(dr);
2897 if (matrix && matrix->isIdentity()) {
2898 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002899 }
reede3b38ce2016-01-08 09:18:44 -08002900 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002901}
2902
2903void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002904 // drawable bounds are no longer reliable (e.g. android displaylist)
2905 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002906 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002907}
2908
reed71c3c762015-06-24 10:29:17 -07002909void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002910 const SkColor colors[], int count, SK_XFERMODE_MODE_PARAM mode,
reed71c3c762015-06-24 10:29:17 -07002911 const SkRect* cull, const SkPaint* paint) {
2912 if (cull && this->quickReject(*cull)) {
2913 return;
2914 }
2915
2916 SkPaint pnt;
2917 if (paint) {
2918 pnt = *paint;
2919 }
halcanary9d524f22016-03-29 09:03:52 -07002920
halcanary96fcdcc2015-08-27 07:41:13 -07002921 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002922 while (iter.next()) {
2923 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2924 }
2925 LOOPER_END
2926}
2927
reedf70b5312016-03-04 16:36:20 -08002928void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2929 SkASSERT(key);
2930
2931 SkPaint paint;
2932 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2933 while (iter.next()) {
2934 iter.fDevice->drawAnnotation(iter, rect, key, value);
2935 }
2936 LOOPER_END
2937}
2938
reed@android.com8a1c16f2008-12-17 15:59:43 +00002939//////////////////////////////////////////////////////////////////////////////
2940// These methods are NOT virtual, and therefore must call back into virtual
2941// methods, rather than actually drawing themselves.
2942//////////////////////////////////////////////////////////////////////////////
2943
reed374772b2016-10-05 17:33:02 -07002944void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002945 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002946 SkPaint paint;
2947
2948 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002949 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002950 this->drawPaint(paint);
2951}
2952
reed374772b2016-10-05 17:33:02 -07002953void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002954 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002955 SkPaint paint;
2956
2957 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002958 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002959 this->drawPaint(paint);
2960}
2961
2962void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002963 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002964 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002965
reed@android.com8a1c16f2008-12-17 15:59:43 +00002966 pt.set(x, y);
2967 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2968}
2969
2970void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002971 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002972 SkPoint pt;
2973 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002974
reed@android.com8a1c16f2008-12-17 15:59:43 +00002975 pt.set(x, y);
2976 paint.setColor(color);
2977 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2978}
2979
2980void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2981 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002982 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002983 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002984
reed@android.com8a1c16f2008-12-17 15:59:43 +00002985 pts[0].set(x0, y0);
2986 pts[1].set(x1, y1);
2987 this->drawPoints(kLines_PointMode, 2, pts, paint);
2988}
2989
2990void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2991 SkScalar right, SkScalar bottom,
2992 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002993 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002994 SkRect r;
2995
2996 r.set(left, top, right, bottom);
2997 this->drawRect(r, paint);
2998}
2999
3000void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3001 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003002 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003003 if (radius < 0) {
3004 radius = 0;
3005 }
3006
3007 SkRect r;
3008 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003009 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003010}
3011
3012void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3013 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003014 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003015 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003016 SkRRect rrect;
3017 rrect.setRectXY(r, rx, ry);
3018 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003019 } else {
3020 this->drawRect(r, paint);
3021 }
3022}
3023
reed@android.com8a1c16f2008-12-17 15:59:43 +00003024void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3025 SkScalar sweepAngle, bool useCenter,
3026 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003027 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003028 if (oval.isEmpty() || !sweepAngle) {
3029 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003030 }
bsalomon21af9ca2016-08-25 12:29:23 -07003031 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003032}
3033
3034void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3035 const SkPath& path, SkScalar hOffset,
3036 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003037 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003038 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003039
reed@android.com8a1c16f2008-12-17 15:59:43 +00003040 matrix.setTranslate(hOffset, vOffset);
3041 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3042}
3043
reed@android.comf76bacf2009-05-13 14:00:33 +00003044///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003045
3046/**
3047 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3048 * against the playback cost of recursing into the subpicture to get at its actual ops.
3049 *
3050 * For now we pick a conservatively small value, though measurement (and other heuristics like
3051 * the type of ops contained) may justify changing this value.
3052 */
3053#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003054
reedd5fa1a42014-08-09 11:08:05 -07003055void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003056 RETURN_ON_NULL(picture);
3057
reed1c2c4412015-04-30 13:09:24 -07003058 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003059 if (matrix && matrix->isIdentity()) {
3060 matrix = nullptr;
3061 }
3062 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3063 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3064 picture->playback(this);
3065 } else {
3066 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003067 }
3068}
robertphillips9b14f262014-06-04 05:40:44 -07003069
reedd5fa1a42014-08-09 11:08:05 -07003070void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3071 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003072 if (!paint || paint->canComputeFastBounds()) {
3073 SkRect bounds = picture->cullRect();
3074 if (paint) {
3075 paint->computeFastBounds(bounds, &bounds);
3076 }
3077 if (matrix) {
3078 matrix->mapRect(&bounds);
3079 }
3080 if (this->quickReject(bounds)) {
3081 return;
3082 }
3083 }
3084
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003085 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003086 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003087}
3088
vjiaoblack95302da2016-07-21 10:25:54 -07003089#ifdef SK_EXPERIMENTAL_SHADOWING
3090void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3091 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003092 const SkPaint* paint,
3093 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003094 RETURN_ON_NULL(picture);
3095
3096 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3097
vjiaoblacke6f5d562016-08-25 06:30:23 -07003098 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003099}
3100
3101void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3102 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003103 const SkPaint* paint,
3104 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003105 if (!paint || paint->canComputeFastBounds()) {
3106 SkRect bounds = picture->cullRect();
3107 if (paint) {
3108 paint->computeFastBounds(bounds, &bounds);
3109 }
3110 if (matrix) {
3111 matrix->mapRect(&bounds);
3112 }
3113 if (this->quickReject(bounds)) {
3114 return;
3115 }
3116 }
3117
3118 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3119
vjiaoblacke6f5d562016-08-25 06:30:23 -07003120 sk_sp<SkImage> povDepthMap;
3121 sk_sp<SkImage> diffuseMap;
3122
vjiaoblack904527d2016-08-09 09:32:09 -07003123 // povDepthMap
3124 {
3125 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003126 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3127 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003128 sk_sp<SkLights> povLight = builder.finish();
3129
3130 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3131 picture->cullRect().height(),
3132 kBGRA_8888_SkColorType,
3133 kOpaque_SkAlphaType);
3134
3135 // Create a new surface (that matches the backend of canvas)
3136 // to create the povDepthMap
3137 sk_sp<SkSurface> surf(this->makeSurface(info));
3138
3139 // Wrap another SPFCanvas around the surface
3140 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3141 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3142
3143 // set the depth map canvas to have the light as the user's POV
3144 depthMapCanvas->setLights(std::move(povLight));
3145
3146 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003147 povDepthMap = surf->makeImageSnapshot();
3148 }
3149
3150 // diffuseMap
3151 {
3152 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3153 picture->cullRect().height(),
3154 kBGRA_8888_SkColorType,
3155 kOpaque_SkAlphaType);
3156
3157 sk_sp<SkSurface> surf(this->makeSurface(info));
3158 surf->getCanvas()->drawPicture(picture);
3159
3160 diffuseMap = surf->makeImageSnapshot();
3161 }
vjiaoblack904527d2016-08-09 09:32:09 -07003162
3163 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3164 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003165 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3166 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003167
3168 // TODO: pass the depth to the shader in vertices, or uniforms
3169 // so we don't have to render depth and color separately
3170 for (int i = 0; i < fLights->numLights(); ++i) {
3171 // skip over ambient lights; they don't cast shadows
3172 // lights that have shadow maps do not need updating (because lights are immutable)
3173 sk_sp<SkImage> depthMap;
3174 SkISize shMapSize;
3175
3176 if (fLights->light(i).getShadowMap() != nullptr) {
3177 continue;
3178 }
3179
3180 if (fLights->light(i).isRadial()) {
3181 shMapSize.fHeight = 1;
3182 shMapSize.fWidth = (int) picture->cullRect().width();
3183
3184 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3185 kBGRA_8888_SkColorType,
3186 kOpaque_SkAlphaType);
3187
3188 // Create new surface (that matches the backend of canvas)
3189 // for each shadow map
3190 sk_sp<SkSurface> surf(this->makeSurface(info));
3191
3192 // Wrap another SPFCanvas around the surface
3193 SkCanvas* depthMapCanvas = surf->getCanvas();
3194
3195 SkLights::Builder builder;
3196 builder.add(fLights->light(i));
3197 sk_sp<SkLights> curLight = builder.finish();
3198
3199 sk_sp<SkShader> shadowMapShader;
3200 shadowMapShader = SkRadialShadowMapShader::Make(
3201 povDepthShader, curLight,
3202 (int) picture->cullRect().width(),
3203 (int) picture->cullRect().height());
3204
3205 SkPaint shadowMapPaint;
3206 shadowMapPaint.setShader(std::move(shadowMapShader));
3207
3208 depthMapCanvas->setLights(curLight);
3209
3210 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3211 diffuseMap->height()),
3212 shadowMapPaint);
3213
3214 depthMap = surf->makeImageSnapshot();
3215
3216 } else {
3217 // TODO: compute the correct size of the depth map from the light properties
3218 // TODO: maybe add a kDepth_8_SkColorType
3219 // TODO: find actual max depth of picture
3220 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3221 fLights->light(i), 255,
3222 (int) picture->cullRect().width(),
3223 (int) picture->cullRect().height());
3224
3225 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3226 kBGRA_8888_SkColorType,
3227 kOpaque_SkAlphaType);
3228
3229 // Create a new surface (that matches the backend of canvas)
3230 // for each shadow map
3231 sk_sp<SkSurface> surf(this->makeSurface(info));
3232
3233 // Wrap another SPFCanvas around the surface
3234 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3235 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3236 depthMapCanvas->setShadowParams(params);
3237
3238 // set the depth map canvas to have the light we're drawing.
3239 SkLights::Builder builder;
3240 builder.add(fLights->light(i));
3241 sk_sp<SkLights> curLight = builder.finish();
3242 depthMapCanvas->setLights(std::move(curLight));
3243
3244 depthMapCanvas->drawPicture(picture);
3245 depthMap = surf->makeImageSnapshot();
3246 }
3247
3248 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3249 fLights->light(i).setShadowMap(std::move(depthMap));
3250 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3251 // we blur the variance map
3252 SkPaint blurPaint;
3253 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3254 params.fShadowRadius, nullptr));
3255
3256 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3257 kBGRA_8888_SkColorType,
3258 kOpaque_SkAlphaType);
3259
3260 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3261
3262 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3263
3264 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3265 }
3266 }
3267
3268 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003269 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3270 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003271 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003272 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003273 diffuseMap->height(),
3274 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003275
3276 shadowPaint.setShader(shadowShader);
3277
3278 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003279}
3280#endif
3281
reed@android.com8a1c16f2008-12-17 15:59:43 +00003282///////////////////////////////////////////////////////////////////////////////
3283///////////////////////////////////////////////////////////////////////////////
3284
reed3aafe112016-08-18 12:45:34 -07003285SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003286 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003287
3288 SkASSERT(canvas);
3289
reed3aafe112016-08-18 12:45:34 -07003290 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003291 fDone = !fImpl->next();
3292}
3293
3294SkCanvas::LayerIter::~LayerIter() {
3295 fImpl->~SkDrawIter();
3296}
3297
3298void SkCanvas::LayerIter::next() {
3299 fDone = !fImpl->next();
3300}
3301
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003302SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003303 return fImpl->getDevice();
3304}
3305
3306const SkMatrix& SkCanvas::LayerIter::matrix() const {
3307 return fImpl->getMatrix();
3308}
3309
3310const SkPaint& SkCanvas::LayerIter::paint() const {
3311 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003312 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003313 paint = &fDefaultPaint;
3314 }
3315 return *paint;
3316}
3317
reed1e7f5e72016-04-27 07:49:17 -07003318const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003319int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3320int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003321
3322///////////////////////////////////////////////////////////////////////////////
3323
fmalitac3b589a2014-06-05 12:40:07 -07003324SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003325
3326///////////////////////////////////////////////////////////////////////////////
3327
3328static bool supported_for_raster_canvas(const SkImageInfo& info) {
3329 switch (info.alphaType()) {
3330 case kPremul_SkAlphaType:
3331 case kOpaque_SkAlphaType:
3332 break;
3333 default:
3334 return false;
3335 }
3336
3337 switch (info.colorType()) {
3338 case kAlpha_8_SkColorType:
3339 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003340 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003341 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003342 break;
3343 default:
3344 return false;
3345 }
3346
3347 return true;
3348}
3349
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003350SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3351 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003352 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003353 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003354
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003355 SkBitmap bitmap;
3356 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003357 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003358 }
halcanary385fe4d2015-08-26 13:07:48 -07003359 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003360}
reedd5fa1a42014-08-09 11:08:05 -07003361
3362///////////////////////////////////////////////////////////////////////////////
3363
3364SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003365 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003366 : fCanvas(canvas)
3367 , fSaveCount(canvas->getSaveCount())
3368{
bsalomon49f085d2014-09-05 13:34:00 -07003369 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003370 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003371 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003372 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003373 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003374 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003375 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003376 canvas->save();
3377 }
mtklein6cfa73a2014-08-13 13:33:49 -07003378
bsalomon49f085d2014-09-05 13:34:00 -07003379 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003380 canvas->concat(*matrix);
3381 }
3382}
3383
3384SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3385 fCanvas->restoreToCount(fSaveCount);
3386}
reede8f30622016-03-23 18:59:25 -07003387
3388#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3389SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
3390 return this->makeSurface(info, props).release();
3391}
3392#endif
reed73603f32016-09-20 08:42:38 -07003393
3394/////////////////////////////////
3395
3396const SkCanvas::ClipOp SkCanvas::kDifference_Op;
3397const SkCanvas::ClipOp SkCanvas::kIntersect_Op;
3398const SkCanvas::ClipOp SkCanvas::kUnion_Op;
3399const SkCanvas::ClipOp SkCanvas::kXOR_Op;
3400const SkCanvas::ClipOp SkCanvas::kReverseDifference_Op;
3401const SkCanvas::ClipOp SkCanvas::kReplace_Op;
3402
3403static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3404static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3405static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3406static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3407static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3408static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");