blob: f3f38386bd1556e36e5a1f54ba352cf4acc16edf [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"
bungemand3ebb482015-08-05 13:57:49 -070013#include "SkDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080018#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070019#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080020#include "SkImage_Base.h"
21#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000022#include "SkMetaData.h"
reed4c21dc52015-06-25 12:32:03 -070023#include "SkNinePatchIter.h"
reedc83a2972015-07-16 07:40:45 -070024#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070025#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000026#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000027#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080028#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000029#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000030#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000031#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070032#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000033#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000034#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080035#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070036
37#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000039#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080040#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000041#include "GrRenderTarget.h"
robertphillips7354a4b2015-12-16 05:08:27 -080042#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000043#endif
44
reede3b38ce2016-01-08 09:18:44 -080045#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
46
reedc83a2972015-07-16 07:40:45 -070047/*
48 * Return true if the drawing this rect would hit every pixels in the canvas.
49 *
50 * Returns false if
51 * - rect does not contain the canvas' bounds
52 * - paint is not fill
53 * - paint would blur or otherwise change the coverage of the rect
54 */
55bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
56 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070057 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
58 (int)kNone_ShaderOverrideOpacity,
59 "need_matching_enums0");
60 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
61 (int)kOpaque_ShaderOverrideOpacity,
62 "need_matching_enums1");
63 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
64 (int)kNotOpaque_ShaderOverrideOpacity,
65 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070066
67 const SkISize size = this->getBaseLayerSize();
68 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
69 if (!this->getClipStack()->quickContains(bounds)) {
70 return false;
71 }
72
73 if (rect) {
74 if (!this->getTotalMatrix().rectStaysRect()) {
75 return false; // conservative
76 }
77
78 SkRect devRect;
79 this->getTotalMatrix().mapRect(&devRect, *rect);
fmalita8c0144c2015-07-22 05:56:16 -070080 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070081 return false;
82 }
83 }
84
85 if (paint) {
86 SkPaint::Style paintStyle = paint->getStyle();
87 if (!(paintStyle == SkPaint::kFill_Style ||
88 paintStyle == SkPaint::kStrokeAndFill_Style)) {
89 return false;
90 }
91 if (paint->getMaskFilter() || paint->getLooper()
92 || paint->getPathEffect() || paint->getImageFilter()) {
93 return false; // conservative
94 }
95 }
96 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
97}
98
99///////////////////////////////////////////////////////////////////////////////////////////////////
100
reedd990e2f2014-12-22 11:58:30 -0800101static bool gIgnoreSaveLayerBounds;
102void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
103 gIgnoreSaveLayerBounds = ignore;
104}
105bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
106 return gIgnoreSaveLayerBounds;
107}
108
reed0acf1b42014-12-22 16:12:38 -0800109static bool gTreatSpriteAsBitmap;
110void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
111 gTreatSpriteAsBitmap = spriteAsBitmap;
112}
113bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
114 return gTreatSpriteAsBitmap;
115}
116
reed@google.comda17f752012-08-16 18:27:05 +0000117// experimental for faster tiled drawing...
118//#define SK_ENABLE_CLIP_QUICKREJECT
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119//#define SK_TRACE_SAVERESTORE
120
121#ifdef SK_TRACE_SAVERESTORE
122 static int gLayerCounter;
123 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
124 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
125
126 static int gRecCounter;
127 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
128 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
129
130 static int gCanvasCounter;
131 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
132 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
133#else
134 #define inc_layer()
135 #define dec_layer()
136 #define inc_rec()
137 #define dec_rec()
138 #define inc_canvas()
139 #define dec_canvas()
140#endif
141
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000142typedef SkTLazy<SkPaint> SkLazyPaint;
143
reedc83a2972015-07-16 07:40:45 -0700144void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000145 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700146 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
147 ? SkSurface::kDiscard_ContentChangeMode
148 : SkSurface::kRetain_ContentChangeMode);
149 }
150}
151
152void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
153 ShaderOverrideOpacity overrideOpacity) {
154 if (fSurfaceBase) {
155 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
156 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
157 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
158 // and therefore we don't care which mode we're in.
159 //
160 if (fSurfaceBase->outstandingImageSnapshot()) {
161 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
162 mode = SkSurface::kDiscard_ContentChangeMode;
163 }
164 }
165 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000166 }
167}
168
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170
reed4a8126e2014-09-22 07:29:03 -0700171static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
172 const uint32_t propFlags = props.flags();
173 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
174 flags &= ~SkPaint::kDither_Flag;
175 }
176 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
177 flags &= ~SkPaint::kAntiAlias_Flag;
178 }
179 return flags;
180}
181
182///////////////////////////////////////////////////////////////////////////////
183
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000184/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 The clip/matrix/proc are fields that reflect the top of the save/restore
186 stack. Whenever the canvas changes, it marks a dirty flag, and then before
187 these are used (assuming we're not on a layer) we rebuild these cache
188 values: they reflect the top of the save stack, but translated and clipped
189 by the device's XY offset and bitmap-bounds.
190*/
191struct DeviceCM {
192 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000193 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000194 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000195 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700196 const SkMatrix* fMatrix;
197 SkMatrix fMatrixStorage;
198 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199
reed96e657d2015-03-10 17:30:07 -0700200 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed86a17e72015-05-14 12:25:22 -0700201 bool conservativeRasterClip, bool deviceIsBitmapDevice)
halcanary96fcdcc2015-08-27 07:41:13 -0700202 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700203 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700204 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700205 {
halcanary96fcdcc2015-08-27 07:41:13 -0700206 if (nullptr != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000208 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 }
reed@google.com4b226022011-01-11 18:32:13 +0000210 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700211 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000212 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000214 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700215 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000216 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 fDevice->unref();
218 }
halcanary385fe4d2015-08-26 13:07:48 -0700219 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000220 }
reed@google.com4b226022011-01-11 18:32:13 +0000221
mtkleinfeaadee2015-04-08 11:25:48 -0700222 void reset(const SkIRect& bounds) {
223 SkASSERT(!fPaint);
224 SkASSERT(!fNext);
225 SkASSERT(fDevice);
226 fClip.setRect(bounds);
227 }
228
reed@google.com045e62d2011-10-24 12:19:46 +0000229 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
230 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000231 int x = fDevice->getOrigin().x();
232 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 int width = fDevice->width();
234 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000235
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 if ((x | y) == 0) {
237 fMatrix = &totalMatrix;
238 fClip = totalClip;
239 } else {
240 fMatrixStorage = totalMatrix;
241 fMatrixStorage.postTranslate(SkIntToScalar(-x),
242 SkIntToScalar(-y));
243 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 totalClip.translate(-x, -y, &fClip);
246 }
247
reed@google.com045e62d2011-10-24 12:19:46 +0000248 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249
250 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000251
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000253 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 SkRegion::kDifference_Op);
255 }
reed@google.com4b226022011-01-11 18:32:13 +0000256
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000257 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
258
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259#ifdef SK_DEBUG
260 if (!fClip.isEmpty()) {
261 SkIRect deviceR;
262 deviceR.set(0, 0, width, height);
263 SkASSERT(deviceR.contains(fClip.getBounds()));
264 }
265#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000266 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267};
268
269/* This is the record we keep for each save/restore level in the stack.
270 Since a level optionally copies the matrix and/or stack, we have pointers
271 for these fields. If the value is copied for this level, the copy is
272 stored in the ...Storage field, and the pointer points to that. If the
273 value is not copied for this level, we ignore ...Storage, and just point
274 at the corresponding value in the previous level in the stack.
275*/
276class SkCanvas::MCRec {
277public:
reed1f836ee2014-07-07 07:49:34 -0700278 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700279 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 /* If there are any layers in the stack, this points to the top-most
281 one that is at or below this level in the stack (so we know what
282 bitmap/device to draw into from this level. This value is NOT
283 reference counted, since the real owner is either our fLayer field,
284 or a previous one in a lower level.)
285 */
reed2ff1fce2014-12-11 07:07:37 -0800286 DeviceCM* fTopLayer;
287 SkRasterClip fRasterClip;
288 SkMatrix fMatrix;
289 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290
reedd9544982014-09-09 18:46:22 -0700291 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700292 fFilter = nullptr;
293 fLayer = nullptr;
294 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800295 fMatrix.reset();
296 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700297
reedd9544982014-09-09 18:46:22 -0700298 // don't bother initializing fNext
299 inc_rec();
300 }
reed2ff1fce2014-12-11 07:07:37 -0800301 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700302 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700303 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700304 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800305 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700306
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307 // don't bother initializing fNext
308 inc_rec();
309 }
310 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000311 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700312 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 dec_rec();
314 }
mtkleinfeaadee2015-04-08 11:25:48 -0700315
316 void reset(const SkIRect& bounds) {
317 SkASSERT(fLayer);
318 SkASSERT(fDeferredSaveCount == 0);
319
320 fMatrix.reset();
321 fRasterClip.setRect(bounds);
322 fLayer->reset(bounds);
323 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324};
325
326class SkDrawIter : public SkDraw {
327public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000328 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000329 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000330 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 canvas->updateDeviceCMCache();
332
reed687fa1c2015-04-07 08:00:56 -0700333 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000335 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 }
reed@google.com4b226022011-01-11 18:32:13 +0000337
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 bool next() {
339 // skip over recs with empty clips
340 if (fSkipEmptyClips) {
341 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
342 fCurrLayer = fCurrLayer->fNext;
343 }
344 }
345
reed@google.comf68c5e22012-02-24 16:38:58 +0000346 const DeviceCM* rec = fCurrLayer;
347 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348
349 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000350 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
351 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700353 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700354 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700355 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000357 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358
359 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700360 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000361
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 return true;
363 }
364 return false;
365 }
reed@google.com4b226022011-01-11 18:32:13 +0000366
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000367 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000368 int getX() const { return fDevice->getOrigin().x(); }
369 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 const SkMatrix& getMatrix() const { return *fMatrix; }
371 const SkRegion& getClip() const { return *fClip; }
372 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000373
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374private:
375 SkCanvas* fCanvas;
376 const DeviceCM* fCurrLayer;
377 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 SkBool8 fSkipEmptyClips;
379
380 typedef SkDraw INHERITED;
381};
382
383/////////////////////////////////////////////////////////////////////////////
384
reeddbc3cef2015-04-29 12:18:57 -0700385static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
386 return lazy->isValid() ? lazy->get() : lazy->set(orig);
387}
388
389/**
390 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700391 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700392 */
393static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700394 SkImageFilter* imgf = paint.getImageFilter();
395 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700396 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700397 }
398
399 SkColorFilter* imgCF;
400 if (!imgf->asAColorFilter(&imgCF)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700401 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700402 }
403
404 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700405 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700406 // there is no existing paint colorfilter, so we can just return the imagefilter's
407 return imgCF;
408 }
409
410 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
411 // and we need to combine them into a single colorfilter.
412 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
413 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700414}
415
senorblanco87e066e2015-10-28 11:23:36 -0700416/**
417 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
418 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
419 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
420 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
421 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
422 * conservative "effective" bounds based on the settings in the paint... with one exception. This
423 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
424 * deliberately ignored.
425 */
426static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
427 const SkRect& rawBounds,
428 SkRect* storage) {
429 SkPaint tmpUnfiltered(paint);
430 tmpUnfiltered.setImageFilter(nullptr);
431 if (tmpUnfiltered.canComputeFastBounds()) {
432 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
433 } else {
434 return rawBounds;
435 }
436}
437
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438class AutoDrawLooper {
439public:
senorblanco87e066e2015-10-28 11:23:36 -0700440 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
441 // paint. It's used to determine the size of the offscreen layer for filters.
442 // If null, the clip will be used instead.
reed4a8126e2014-09-22 07:29:03 -0700443 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000444 bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700445 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000446 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800447#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800449#else
450 fFilter = nullptr;
451#endif
reed4a8126e2014-09-22 07:29:03 -0700452 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000453 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700454 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000455 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456
reeddbc3cef2015-04-29 12:18:57 -0700457 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
458 if (simplifiedCF) {
459 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
460 paint->setColorFilter(simplifiedCF)->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700461 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700462 fPaint = paint;
463 }
464
465 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700466 /**
467 * We implement ImageFilters for a given draw by creating a layer, then applying the
468 * imagefilter to the pixels of that layer (its backing surface/image), and then
469 * we call restore() to xfer that layer to the main canvas.
470 *
471 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
472 * 2. Generate the src pixels:
473 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
474 * return (fPaint). We then draw the primitive (using srcover) into a cleared
475 * buffer/surface.
476 * 3. Restore the layer created in #1
477 * The imagefilter is passed the buffer/surface from the layer (now filled with the
478 * src pixels of the primitive). It returns a new "filtered" buffer, which we
479 * draw onto the previous layer using the xfermode from the original paint.
480 */
reed@google.com8926b162012-03-23 15:36:36 +0000481 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700482 tmp.setImageFilter(fPaint->getImageFilter());
483 tmp.setXfermode(fPaint->getXfermode());
senorblanco87e066e2015-10-28 11:23:36 -0700484 SkRect storage;
485 if (rawBounds) {
486 // Make rawBounds include all paint outsets except for those due to image filters.
487 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
488 }
reedbfd5f172016-01-07 11:28:08 -0800489 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700490 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700491 fTempLayerForImageFilter = true;
492 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000493 }
494
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000495 if (SkDrawLooper* looper = paint.getLooper()) {
496 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
497 looper->contextSize());
498 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000499 fIsSimple = false;
500 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700501 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000502 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700503 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000504 }
piotaixrb5fae932014-09-24 13:03:30 -0700505
reed4a8126e2014-09-22 07:29:03 -0700506 uint32_t oldFlags = paint.getFlags();
507 fNewPaintFlags = filter_paint_flags(props, oldFlags);
508 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700509 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700510 paint->setFlags(fNewPaintFlags);
511 fPaint = paint;
512 // if we're not simple, doNext() will take care of calling setFlags()
513 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700517 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000518 fCanvas->internalRestore();
519 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000520 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000522
reed@google.com4e2b3d32011-04-07 14:18:59 +0000523 const SkPaint& paint() const {
524 SkASSERT(fPaint);
525 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000527
reed@google.com129ec222012-05-15 13:24:09 +0000528 bool next(SkDrawFilter::Type drawType) {
529 if (fDone) {
530 return false;
531 } else if (fIsSimple) {
532 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000533 return !fPaint->nothingToDraw();
534 } else {
535 return this->doNext(drawType);
536 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000537 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000538
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539private:
reeddbc3cef2015-04-29 12:18:57 -0700540 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
541 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000542 SkCanvas* fCanvas;
543 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000544 SkDrawFilter* fFilter;
545 const SkPaint* fPaint;
546 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700547 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700548 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000549 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000550 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000551 SkDrawLooper::Context* fLooperContext;
552 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000553
554 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555};
556
reed@google.com129ec222012-05-15 13:24:09 +0000557bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700558 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000559 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700560 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000561
reeddbc3cef2015-04-29 12:18:57 -0700562 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
563 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700564 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000565
reed5c476fb2015-04-20 08:04:21 -0700566 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700567 paint->setImageFilter(nullptr);
568 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000569 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000570
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000571 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000572 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000573 return false;
574 }
575 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000576 if (!fFilter->filter(paint, drawType)) {
577 fDone = true;
578 return false;
579 }
halcanary96fcdcc2015-08-27 07:41:13 -0700580 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000581 // no looper means we only draw once
582 fDone = true;
583 }
584 }
585 fPaint = paint;
586
587 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000588 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000589 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000590 }
591
592 // call this after any possible paint modifiers
593 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700594 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000595 return false;
596 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000597 return true;
598}
599
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600////////// macros to place around the internal draw calls //////////////////
601
reed262a71b2015-12-05 13:07:27 -0800602#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
603 this->predrawNotify(); \
604 AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \
605 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
606 SkDrawIter iter(this);
607
608
reed@google.com8926b162012-03-23 15:36:36 +0000609#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000610 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700611 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000612 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000613 SkDrawIter iter(this);
614
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000615#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000616 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700617 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000618 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000620
reedc83a2972015-07-16 07:40:45 -0700621#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
622 this->predrawNotify(bounds, &paint, auxOpaque); \
623 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
624 while (looper.next(type)) { \
625 SkDrawIter iter(this);
626
reed@google.com4e2b3d32011-04-07 14:18:59 +0000627#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628
629////////////////////////////////////////////////////////////////////////////
630
mtkleinfeaadee2015-04-08 11:25:48 -0700631void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
632 this->restoreToCount(1);
633 fCachedLocalClipBounds.setEmpty();
634 fCachedLocalClipBoundsDirty = true;
635 fClipStack->reset();
636 fMCRec->reset(bounds);
637
638 // We're peering through a lot of structs here. Only at this scope do we
639 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
640 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
641}
642
reedd9544982014-09-09 18:46:22 -0700643SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800644 if (device && device->forceConservativeRasterClip()) {
645 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
646 }
647 // Since init() is only called once by our constructors, it is safe to perform this
648 // const-cast.
649 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
650
reed@google.comc0784db2013-12-13 21:16:12 +0000651 fCachedLocalClipBounds.setEmpty();
652 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000653 fAllowSoftClip = true;
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;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658
halcanary385fe4d2015-08-26 13:07:48 -0700659 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700660
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700662 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663
reeda499f902015-05-01 09:34:31 -0700664 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
665 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700666 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700667
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669
halcanary96fcdcc2015-08-27 07:41:13 -0700670 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000671
reedf92c8662014-08-18 08:02:43 -0700672 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700673 // The root device and the canvas should always have the same pixel geometry
674 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700675 device->onAttachToCanvas(this);
676 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800677 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700678 }
679 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680}
681
reed@google.comcde92112011-07-06 20:00:52 +0000682SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000683 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700684 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800685 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000686{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000687 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000688
halcanary96fcdcc2015-08-27 07:41:13 -0700689 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000690}
691
reedd9544982014-09-09 18:46:22 -0700692static SkBitmap make_nopixels(int width, int height) {
693 SkBitmap bitmap;
694 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
695 return bitmap;
696}
697
698class SkNoPixelsBitmapDevice : public SkBitmapDevice {
699public:
robertphillipsfcf78292015-06-19 11:49:52 -0700700 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
701 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800702 {
703 this->setOrigin(bounds.x(), bounds.y());
704 }
reedd9544982014-09-09 18:46:22 -0700705
706private:
piotaixrb5fae932014-09-24 13:03:30 -0700707
reedd9544982014-09-09 18:46:22 -0700708 typedef SkBitmapDevice INHERITED;
709};
710
reed96a857e2015-01-25 10:33:58 -0800711SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000712 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800713 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800714 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000715{
716 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700717
halcanary385fe4d2015-08-26 13:07:48 -0700718 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
719 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700720}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000721
reed78e27682014-11-19 08:04:34 -0800722SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700723 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700724 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800725 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700726{
727 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700728
halcanary385fe4d2015-08-26 13:07:48 -0700729 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700730}
731
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000732SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000733 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700734 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800735 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000736{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000737 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700738
reedd9544982014-09-09 18:46:22 -0700739 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740}
741
robertphillipsfcf78292015-06-19 11:49:52 -0700742SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
743 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700744 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800745 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700746{
747 inc_canvas();
748
749 this->init(device, flags);
750}
751
reed4a8126e2014-09-22 07:29:03 -0700752SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700753 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700754 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800755 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700756{
757 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700758
halcanary385fe4d2015-08-26 13:07:48 -0700759 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700760 this->init(device, kDefault_InitFlags);
761}
reed29c857d2014-09-21 10:25:07 -0700762
reed4a8126e2014-09-22 07:29:03 -0700763SkCanvas::SkCanvas(const SkBitmap& bitmap)
764 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
765 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800766 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700767{
768 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700769
halcanary385fe4d2015-08-26 13:07:48 -0700770 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700771 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772}
773
774SkCanvas::~SkCanvas() {
775 // free up the contents of our deque
776 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000777
reed@android.com8a1c16f2008-12-17 15:59:43 +0000778 this->internalRestore(); // restore the last, since we're going away
779
halcanary385fe4d2015-08-26 13:07:48 -0700780 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000781
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782 dec_canvas();
783}
784
fmalita53d9f1c2016-01-25 06:23:54 -0800785#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786SkDrawFilter* SkCanvas::getDrawFilter() const {
787 return fMCRec->fFilter;
788}
789
790SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700791 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
793 return filter;
794}
fmalita77650002016-01-21 18:47:11 -0800795#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000797SkMetaData& SkCanvas::getMetaData() {
798 // metadata users are rare, so we lazily allocate it. If that changes we
799 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700800 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000801 fMetaData = new SkMetaData;
802 }
803 return *fMetaData;
804}
805
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806///////////////////////////////////////////////////////////////////////////////
807
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000808void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000809 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000810 if (device) {
811 device->flush();
812 }
813}
814
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000815SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000816 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000817 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
818}
819
senorblancoafc7cce2016-02-02 18:44:15 -0800820SkIRect SkCanvas::getTopLayerBounds() const {
821 SkBaseDevice* d = this->getTopDevice();
822 if (!d) {
823 return SkIRect::MakeEmpty();
824 }
825 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
826}
827
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000828SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000829 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000830 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831 SkASSERT(rec && rec->fLayer);
832 return rec->fLayer->fDevice;
833}
834
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000835SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000836 if (updateMatrixClip) {
837 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
838 }
reed@google.com9266fed2011-03-30 00:18:03 +0000839 return fMCRec->fTopLayer->fDevice;
840}
841
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000842bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
843 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
844 return false;
845 }
846
847 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700848 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700849 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000850 return false;
851 }
852 weAllocated = true;
853 }
854
reedcf01e312015-05-23 19:14:51 -0700855 SkAutoPixmapUnlock unlocker;
856 if (bitmap->requestLock(&unlocker)) {
857 const SkPixmap& pm = unlocker.pixmap();
858 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
859 return true;
860 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000861 }
862
863 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700864 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000865 }
866 return false;
867}
reed@google.com51df9e32010-12-23 19:29:18 +0000868
bsalomon@google.comc6980972011-11-02 19:57:21 +0000869bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000870 SkIRect r = srcRect;
871 const SkISize size = this->getBaseLayerSize();
872 if (!r.intersect(0, 0, size.width(), size.height())) {
873 bitmap->reset();
874 return false;
875 }
876
reed84825042014-09-02 12:50:45 -0700877 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000878 // bitmap will already be reset.
879 return false;
880 }
881 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
882 bitmap->reset();
883 return false;
884 }
885 return true;
886}
887
reed96472de2014-12-10 09:53:42 -0800888bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000889 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000890 if (!device) {
891 return false;
892 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000893 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800894
reed96472de2014-12-10 09:53:42 -0800895 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
896 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000897 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000898 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000899
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000900 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800901 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000902}
903
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000904bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
905 if (bitmap.getTexture()) {
906 return false;
907 }
reedcf01e312015-05-23 19:14:51 -0700908
909 SkAutoPixmapUnlock unlocker;
910 if (bitmap.requestLock(&unlocker)) {
911 const SkPixmap& pm = unlocker.pixmap();
912 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000913 }
914 return false;
915}
916
917bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
918 int x, int y) {
919 switch (origInfo.colorType()) {
920 case kUnknown_SkColorType:
921 case kIndex_8_SkColorType:
922 return false;
923 default:
924 break;
925 }
halcanary96fcdcc2015-08-27 07:41:13 -0700926 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000927 return false;
928 }
929
930 const SkISize size = this->getBaseLayerSize();
931 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
932 if (!target.intersect(0, 0, size.width(), size.height())) {
933 return false;
934 }
935
936 SkBaseDevice* device = this->getDevice();
937 if (!device) {
938 return false;
939 }
940
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000941 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700942 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000943
944 // if x or y are negative, then we have to adjust pixels
945 if (x > 0) {
946 x = 0;
947 }
948 if (y > 0) {
949 y = 0;
950 }
951 // here x,y are either 0 or negative
952 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
953
reed4af35f32014-06-27 17:47:49 -0700954 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700955 const bool completeOverwrite = info.dimensions() == size;
956 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700957
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000958 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000959 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000960}
reed@google.com51df9e32010-12-23 19:29:18 +0000961
junov@google.com4370aed2012-01-18 16:21:08 +0000962SkCanvas* SkCanvas::canvasForDrawIter() {
963 return this;
964}
965
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966//////////////////////////////////////////////////////////////////////////////
967
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968void SkCanvas::updateDeviceCMCache() {
969 if (fDeviceCMDirty) {
970 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700971 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000972 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000973
halcanary96fcdcc2015-08-27 07:41:13 -0700974 if (nullptr == layer->fNext) { // only one layer
975 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000977 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 do {
reed687fa1c2015-04-07 08:00:56 -0700979 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700980 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 }
982 fDeviceCMDirty = false;
983 }
984}
985
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986///////////////////////////////////////////////////////////////////////////////
987
reed2ff1fce2014-12-11 07:07:37 -0800988void SkCanvas::checkForDeferredSave() {
989 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800990 this->doSave();
991 }
992}
993
reedf0090cb2014-11-26 08:55:51 -0800994int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800995#ifdef SK_DEBUG
996 int count = 0;
997 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
998 for (;;) {
999 const MCRec* rec = (const MCRec*)iter.next();
1000 if (!rec) {
1001 break;
1002 }
1003 count += 1 + rec->fDeferredSaveCount;
1004 }
1005 SkASSERT(count == fSaveCount);
1006#endif
1007 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001008}
1009
1010int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001011 fSaveCount += 1;
1012 fMCRec->fDeferredSaveCount += 1;
1013 return this->getSaveCount() - 1; // return our prev value
1014}
1015
1016void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001017 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001018
1019 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1020 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001021 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001022}
1023
1024void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001025 if (fMCRec->fDeferredSaveCount > 0) {
1026 SkASSERT(fSaveCount > 1);
1027 fSaveCount -= 1;
1028 fMCRec->fDeferredSaveCount -= 1;
1029 } else {
1030 // check for underflow
1031 if (fMCStack.count() > 1) {
1032 this->willRestore();
1033 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001034 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001035 this->internalRestore();
1036 this->didRestore();
1037 }
reedf0090cb2014-11-26 08:55:51 -08001038 }
1039}
1040
1041void SkCanvas::restoreToCount(int count) {
1042 // sanity check
1043 if (count < 1) {
1044 count = 1;
1045 }
mtkleinf0f14112014-12-12 08:46:25 -08001046
reedf0090cb2014-11-26 08:55:51 -08001047 int n = this->getSaveCount() - count;
1048 for (int i = 0; i < n; ++i) {
1049 this->restore();
1050 }
1051}
1052
reed2ff1fce2014-12-11 07:07:37 -08001053void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001055 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001057
reed687fa1c2015-04-07 08:00:56 -07001058 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059}
1060
reed4960eee2015-12-18 07:09:18 -08001061bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001062#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001063 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@google.comb93ba452014-03-10 19:47:58 +00001064#else
1065 return true;
1066#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067}
1068
reed4960eee2015-12-18 07:09:18 -08001069bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001070 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001071 SkIRect clipBounds;
1072 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001073 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001074 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001075
reed96e657d2015-03-10 17:30:07 -07001076 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1077
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001078 if (imageFilter) {
reed1d524692016-02-22 05:57:31 -08001079 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblancodb64af32015-12-09 10:11:43 -08001080 if (bounds && !imageFilter->canComputeFastBounds()) {
1081 bounds = nullptr;
1082 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001083 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001084 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001085 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001087
reed96e657d2015-03-10 17:30:07 -07001088 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089 r.roundOut(&ir);
1090 // early exit if the layer's bounds are clipped out
1091 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001092 if (BoundsAffectsClip(saveLayerFlags)) {
reed9b3aa542015-03-11 08:47:12 -07001093 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001094 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001095 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001096 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097 }
1098 } else { // no user bounds, so just use the clip
1099 ir = clipBounds;
1100 }
reed180aec42015-03-11 10:39:04 -07001101 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001102
reed4960eee2015-12-18 07:09:18 -08001103 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001104 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -07001105 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -07001106 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001107 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001108 }
1109
1110 if (intersection) {
1111 *intersection = ir;
1112 }
1113 return true;
1114}
1115
reed4960eee2015-12-18 07:09:18 -08001116
reed4960eee2015-12-18 07:09:18 -08001117int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1118 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001119}
1120
reed70ee31b2015-12-10 13:44:45 -08001121int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001122 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1123}
1124
1125int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1126 SaveLayerRec rec(origRec);
1127 if (gIgnoreSaveLayerBounds) {
1128 rec.fBounds = nullptr;
1129 }
1130 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1131 fSaveCount += 1;
1132 this->internalSaveLayer(rec, strategy);
1133 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001134}
1135
reedbfd5f172016-01-07 11:28:08 -08001136static void draw_filter_into_device(SkBaseDevice* src, const SkImageFilter* filter,
1137 SkBaseDevice* dst, const SkMatrix& ctm) {
robertphillips7354a4b2015-12-16 05:08:27 -08001138
1139 SkBitmap srcBM;
1140
1141#if SK_SUPPORT_GPU
1142 GrRenderTarget* srcRT = src->accessRenderTarget();
1143 if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) {
1144 // When both the src & the dst are on the gpu but the src doesn't have a texture,
1145 // we create a temporary texture for the draw.
1146 // TODO: we should actually only copy the portion of the source needed to apply the image
1147 // filter
1148 GrContext* context = srcRT->getContext();
bsalomon5ec26ae2016-02-25 08:33:02 -08001149 SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(srcRT->desc(),
1150 SkBudgeted::kYes));
robertphillips7354a4b2015-12-16 05:08:27 -08001151
1152 context->copySurface(tex, srcRT);
1153
1154 GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM);
1155 } else
1156#endif
1157 {
1158 srcBM = src->accessBitmap(false);
1159 }
1160
1161 SkCanvas c(dst);
1162
reedbfd5f172016-01-07 11:28:08 -08001163 SkAutoTUnref<SkImageFilter> localF(filter->newWithLocalMatrix(ctm));
robertphillips7354a4b2015-12-16 05:08:27 -08001164 SkPaint p;
reedbfd5f172016-01-07 11:28:08 -08001165 p.setImageFilter(localF);
1166 const SkScalar x = SkIntToScalar(src->getOrigin().x());
1167 const SkScalar y = SkIntToScalar(src->getOrigin().y());
1168 c.drawBitmap(srcBM, x, y, &p);
robertphillips7354a4b2015-12-16 05:08:27 -08001169}
reed70ee31b2015-12-10 13:44:45 -08001170
reed129ed1c2016-02-22 06:42:31 -08001171static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1172 const SkPaint* paint) {
1173 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1174 // e.g. sRGB or F16, we can remove this check
1175 const bool hasImageFilter = paint && paint->getImageFilter();
1176
1177 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1178 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1179 // force to L32
1180 return SkImageInfo::MakeN32(w, h, alphaType);
1181 } else {
1182 // keep the same characteristics as the prev
1183 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.profileType());
1184 }
1185}
1186
reed4960eee2015-12-18 07:09:18 -08001187void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1188 const SkRect* bounds = rec.fBounds;
1189 const SkPaint* paint = rec.fPaint;
1190 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1191
reed@google.comb93ba452014-03-10 19:47:58 +00001192#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001193 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001194#endif
1195
junov@chromium.orga907ac32012-02-24 21:54:07 +00001196 // do this before we create the layer. We don't call the public save() since
1197 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001198 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001199
1200 fDeviceCMDirty = true;
1201
1202 SkIRect ir;
reed4960eee2015-12-18 07:09:18 -08001203 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001204 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001205 }
1206
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001207 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1208 // the clipRectBounds() call above?
1209 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001210 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001211 }
1212
reed4960eee2015-12-18 07:09:18 -08001213 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001214 SkPixelGeometry geo = fProps.pixelGeometry();
1215 if (paint) {
reed76033be2015-03-14 10:54:31 -07001216 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001217 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001218 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001219 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001220 }
1221 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222
reedb2db8982014-11-13 12:41:02 -08001223 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001224 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001225 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001226 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001227 }
reedb2db8982014-11-13 12:41:02 -08001228
reed129ed1c2016-02-22 06:42:31 -08001229 SkImageInfo info = make_layer_info(device->imageInfo(), ir.width(), ir.height(), isOpaque,
1230 paint);
1231
reed61f501f2015-04-29 08:34:00 -07001232 bool forceSpriteOnRestore = false;
1233 {
reed70ee31b2015-12-10 13:44:45 -08001234 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001235 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001236 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001237 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1238 preserveLCDText, false);
reed61f501f2015-04-29 08:34:00 -07001239 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001240 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001241 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001242 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1243 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001244 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001245 SkErrorInternals::SetError(kInternalError_SkError,
1246 "Unable to create device for layer.");
1247 return;
1248 }
1249 forceSpriteOnRestore = true;
1250 }
1251 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001252 }
reed@google.com6f8f2922011-03-04 22:27:10 +00001253 device->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001254
reedbfd5f172016-01-07 11:28:08 -08001255 if (rec.fBackdrop) {
1256 draw_filter_into_device(fMCRec->fTopLayer->fDevice, rec.fBackdrop, device, fMCRec->fMatrix);
robertphillips7354a4b2015-12-16 05:08:27 -08001257 }
1258
halcanary385fe4d2015-08-26 13:07:48 -07001259 DeviceCM* layer =
1260 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001261 device->unref();
1262
1263 layer->fNext = fMCRec->fTopLayer;
1264 fMCRec->fLayer = layer;
1265 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266}
1267
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001268int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001269 if (0xFF == alpha) {
1270 return this->saveLayer(bounds, nullptr);
1271 } else {
1272 SkPaint tmpPaint;
1273 tmpPaint.setAlpha(alpha);
1274 return this->saveLayer(bounds, &tmpPaint);
1275 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001276}
1277
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278void SkCanvas::internalRestore() {
1279 SkASSERT(fMCStack.count() != 0);
1280
1281 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001282 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283
reed687fa1c2015-04-07 08:00:56 -07001284 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001285
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001286 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001287 DeviceCM* layer = fMCRec->fLayer; // may be null
1288 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001289 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290
1291 // now do the normal restore()
1292 fMCRec->~MCRec(); // balanced in save()
1293 fMCStack.pop_back();
1294 fMCRec = (MCRec*)fMCStack.back();
1295
1296 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1297 since if we're being recorded, we don't want to record this (the
1298 recorder will have already recorded the restore).
1299 */
bsalomon49f085d2014-09-05 13:34:00 -07001300 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001302 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001303 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001304 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001305 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001307 delete layer;
reedb679ca82015-04-07 04:40:48 -07001308 } else {
1309 // we're at the root
reeda499f902015-05-01 09:34:31 -07001310 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001311 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001312 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001313 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314}
1315
reed4a8126e2014-09-22 07:29:03 -07001316SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001317 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001318 props = &fProps;
1319 }
1320 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001321}
1322
reed4a8126e2014-09-22 07:29:03 -07001323SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001324 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001325 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001326}
1327
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001328SkImageInfo SkCanvas::imageInfo() const {
1329 SkBaseDevice* dev = this->getDevice();
1330 if (dev) {
1331 return dev->imageInfo();
1332 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001333 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001334 }
1335}
1336
1337const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001338 SkPixmap pmap;
1339 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001340 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001341 }
1342 if (info) {
1343 *info = pmap.info();
1344 }
1345 if (rowBytes) {
1346 *rowBytes = pmap.rowBytes();
1347 }
1348 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001349}
1350
reed884e97c2015-05-26 11:31:54 -07001351bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001352 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001353 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001354}
1355
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001356void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001357 SkPixmap pmap;
1358 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001359 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001360 }
1361 if (info) {
1362 *info = pmap.info();
1363 }
1364 if (rowBytes) {
1365 *rowBytes = pmap.rowBytes();
1366 }
1367 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001368 *origin = this->getTopDevice(false)->getOrigin();
1369 }
reed884e97c2015-05-26 11:31:54 -07001370 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001371}
1372
reed884e97c2015-05-26 11:31:54 -07001373bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001374 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001375 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001376}
1377
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001380void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001381 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001383 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001384 paint = &tmp;
1385 }
reed@google.com4b226022011-01-11 18:32:13 +00001386
reed@google.com8926b162012-03-23 15:36:36 +00001387 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001389 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001390 paint = &looper.paint();
1391 SkImageFilter* filter = paint->getImageFilter();
1392 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001393 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001394 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001395 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001396 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001397 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001398 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001399 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblancodb64af32015-12-09 10:11:43 -08001400 SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
senorblancobe129b22014-08-08 07:14:35 -07001401 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reed4e23cda2016-01-11 10:56:59 -08001402 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
robertphillips48e78462016-02-17 13:57:16 -08001403 if (filter->filterImageDeprecated(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001404 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001405 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001406 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1407 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001408 }
reed61f501f2015-04-29 08:34:00 -07001409 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001410 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001411 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001412 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001413 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001414 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001416 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001417}
1418
reed32704672015-12-16 08:27:10 -08001419/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001420
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001421void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001422 SkMatrix m;
1423 m.setTranslate(dx, dy);
1424 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001425}
1426
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001427void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001428 SkMatrix m;
1429 m.setScale(sx, sy);
1430 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431}
1432
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001433void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001434 SkMatrix m;
1435 m.setRotate(degrees);
1436 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001437}
1438
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001439void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001440 SkMatrix m;
1441 m.setSkew(sx, sy);
1442 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001443}
1444
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001445void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001446 if (matrix.isIdentity()) {
1447 return;
1448 }
1449
reed2ff1fce2014-12-11 07:07:37 -08001450 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001451 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001452 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001453 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001454
1455 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001456}
1457
reed86a17e72015-05-14 12:25:22 -07001458void SkCanvas::setMatrix(const SkMatrix& matrix) {
1459 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001460 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001461 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001462 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001463 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001464}
1465
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466void SkCanvas::resetMatrix() {
1467 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001468
reed@android.com8a1c16f2008-12-17 15:59:43 +00001469 matrix.reset();
1470 this->setMatrix(matrix);
1471}
1472
1473//////////////////////////////////////////////////////////////////////////////
1474
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001475void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001476 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001477 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1478 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001479}
1480
1481void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001482#ifdef SK_ENABLE_CLIP_QUICKREJECT
1483 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001484 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001485 return false;
1486 }
1487
reed@google.com3b3e8952012-08-16 20:53:31 +00001488 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001489 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001490 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001491
reed687fa1c2015-04-07 08:00:56 -07001492 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001493 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001494 }
1495 }
1496#endif
1497
bsalomonac8cabd2015-11-20 18:53:07 -08001498 if (!fAllowSoftClip) {
1499 edgeStyle = kHard_ClipEdgeStyle;
1500 }
reed90ba0952015-11-20 13:42:47 -08001501
reedc64eff52015-11-21 12:39:45 -08001502 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1503 SkRect devR;
1504 if (rectStaysRect) {
1505 fMCRec->fMatrix.mapRect(&devR, rect);
1506 }
bsalomonac8cabd2015-11-20 18:53:07 -08001507
reedc64eff52015-11-21 12:39:45 -08001508 // Check if we can quick-accept the clip call (and do nothing)
1509 //
1510 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1511 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1512 // might allow lazy save/restores to eliminate entire save/restore blocks.
1513 //
1514 if (SkRegion::kIntersect_Op == op &&
1515 kHard_ClipEdgeStyle == edgeStyle
1516 && rectStaysRect)
1517 {
1518 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1519#if 0
1520 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1521 rect.left(), rect.top(), rect.right(), rect.bottom());
1522#endif
1523 return;
1524 }
1525 }
1526
1527 AutoValidateClip avc(this);
1528
1529 fDeviceCMDirty = true;
1530 fCachedLocalClipBoundsDirty = true;
1531
1532 if (rectStaysRect) {
1533 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1534 fClipStack->clipDevRect(devR, op, isAA);
senorblancoafc7cce2016-02-02 18:44:15 -08001535 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001536 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001537 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001538 // and clip against that, since it can handle any matrix. However, to
1539 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1540 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001541 SkPath path;
1542
1543 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001544 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001545 }
1546}
1547
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001548void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001549 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001550 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001551 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001552 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1553 } else {
1554 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001555 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001556}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001557
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001558void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001559 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001560 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001561 AutoValidateClip avc(this);
1562
1563 fDeviceCMDirty = true;
1564 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001565 if (!fAllowSoftClip) {
1566 edgeStyle = kHard_ClipEdgeStyle;
1567 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001568
reed687fa1c2015-04-07 08:00:56 -07001569 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001570
senorblancoafc7cce2016-02-02 18:44:15 -08001571 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
robertphillips125f19a2015-11-23 09:00:05 -08001572 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001573 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001574 }
1575
1576 SkPath path;
1577 path.addRRect(rrect);
1578 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001579 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001580}
1581
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001582void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001583 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001584 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001585
1586 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1587 SkRect r;
1588 if (path.isRect(&r)) {
1589 this->onClipRect(r, op, edgeStyle);
1590 return;
1591 }
1592 SkRRect rrect;
1593 if (path.isOval(&r)) {
1594 rrect.setOval(r);
1595 this->onClipRRect(rrect, op, edgeStyle);
1596 return;
1597 }
1598 if (path.isRRect(&rrect)) {
1599 this->onClipRRect(rrect, op, edgeStyle);
1600 return;
1601 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001602 }
robertphillips39f05382015-11-24 09:30:12 -08001603
1604 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001605}
1606
1607void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001608#ifdef SK_ENABLE_CLIP_QUICKREJECT
1609 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001610 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001611 return false;
1612 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001613
reed@google.com3b3e8952012-08-16 20:53:31 +00001614 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001615 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001616 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001617
reed687fa1c2015-04-07 08:00:56 -07001618 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001619 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001620 }
1621 }
1622#endif
1623
reed@google.com5c3d1472011-02-22 19:12:23 +00001624 AutoValidateClip avc(this);
1625
reed@android.com8a1c16f2008-12-17 15:59:43 +00001626 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001627 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001628 if (!fAllowSoftClip) {
1629 edgeStyle = kHard_ClipEdgeStyle;
1630 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001631
1632 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001633 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001634
reed@google.comfe701122011-11-08 19:41:23 +00001635 // Check if the transfomation, or the original path itself
1636 // made us empty. Note this can also happen if we contained NaN
1637 // values. computing the bounds detects this, and will set our
1638 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1639 if (devPath.getBounds().isEmpty()) {
1640 // resetting the path will remove any NaN or other wanky values
1641 // that might upset our scan converter.
1642 devPath.reset();
1643 }
1644
reed@google.com5c3d1472011-02-22 19:12:23 +00001645 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001646 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001647
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001648 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001649 bool clipIsAA = getClipStack()->asPath(&devPath);
1650 if (clipIsAA) {
1651 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001652 }
fmalita1a481fe2015-02-04 07:39:34 -08001653
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001654 op = SkRegion::kReplace_Op;
1655 }
1656
senorblancoafc7cce2016-02-02 18:44:15 -08001657 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658}
1659
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001660void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001661 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001662 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001663}
1664
1665void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001666 AutoValidateClip avc(this);
1667
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001669 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001670
reed@google.com5c3d1472011-02-22 19:12:23 +00001671 // todo: signal fClipStack that we have a region, and therefore (I guess)
1672 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001673 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001674
reed1f836ee2014-07-07 07:49:34 -07001675 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001676}
1677
reed@google.com819c9212011-02-23 18:56:55 +00001678#ifdef SK_DEBUG
1679void SkCanvas::validateClip() const {
1680 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001681 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001682 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001683 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001684 return;
1685 }
1686
reed@google.com819c9212011-02-23 18:56:55 +00001687 SkIRect ir;
1688 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001689 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001690
reed687fa1c2015-04-07 08:00:56 -07001691 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001692 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001693 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001694 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001695 case SkClipStack::Element::kRect_Type:
1696 element->getRect().round(&ir);
1697 tmpClip.op(ir, element->getOp());
1698 break;
1699 case SkClipStack::Element::kEmpty_Type:
1700 tmpClip.setEmpty();
1701 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001702 default: {
1703 SkPath path;
1704 element->asPath(&path);
senorblancoafc7cce2016-02-02 18:44:15 -08001705 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001706 break;
1707 }
reed@google.com819c9212011-02-23 18:56:55 +00001708 }
1709 }
reed@google.com819c9212011-02-23 18:56:55 +00001710}
1711#endif
1712
reed@google.com90c07ea2012-04-13 13:50:27 +00001713void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001714 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001715 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001716
halcanary96fcdcc2015-08-27 07:41:13 -07001717 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001718 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001719 }
1720}
1721
reed@google.com5c3d1472011-02-22 19:12:23 +00001722///////////////////////////////////////////////////////////////////////////////
1723
reed@google.com754de5f2014-02-24 19:38:20 +00001724bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001725 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001726}
1727
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001728bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001729 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001730}
1731
reed@google.com3b3e8952012-08-16 20:53:31 +00001732bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001733 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001734 return true;
1735
reed1f836ee2014-07-07 07:49:34 -07001736 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001737 return true;
1738 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739
reed1f836ee2014-07-07 07:49:34 -07001740 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001741 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001742 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001743 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001744 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001745 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001746
reed@android.coma380ae42009-07-21 01:17:02 +00001747 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001748 // TODO: should we use | instead, or compare all 4 at once?
1749 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001750 return true;
1751 }
reed@google.comc0784db2013-12-13 21:16:12 +00001752 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001753 return true;
1754 }
1755 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001756 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001757}
1758
reed@google.com3b3e8952012-08-16 20:53:31 +00001759bool SkCanvas::quickReject(const SkPath& path) const {
1760 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001761}
1762
reed@google.com3b3e8952012-08-16 20:53:31 +00001763bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001764 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001765 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001766 return false;
1767 }
1768
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001769 SkMatrix inverse;
1770 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001771 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001772 if (bounds) {
1773 bounds->setEmpty();
1774 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001775 return false;
1776 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001777
bsalomon49f085d2014-09-05 13:34:00 -07001778 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001779 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001780 // adjust it outwards in case we are antialiasing
1781 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001782
reed@google.com8f4d2302013-12-17 16:44:46 +00001783 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1784 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001785 inverse.mapRect(bounds, r);
1786 }
1787 return true;
1788}
1789
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001790bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001791 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001792 if (clip.isEmpty()) {
1793 if (bounds) {
1794 bounds->setEmpty();
1795 }
1796 return false;
1797 }
1798
bsalomon49f085d2014-09-05 13:34:00 -07001799 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001800 *bounds = clip.getBounds();
1801 }
1802 return true;
1803}
1804
reed@android.com8a1c16f2008-12-17 15:59:43 +00001805const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001806 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001807}
1808
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001809const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001810 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001811}
1812
reed@google.com9c135db2014-03-12 18:28:35 +00001813GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1814 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001815 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001816}
1817
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001818GrContext* SkCanvas::getGrContext() {
1819#if SK_SUPPORT_GPU
1820 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001821 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001822 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001823 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001824 return renderTarget->getContext();
1825 }
1826 }
1827#endif
1828
halcanary96fcdcc2015-08-27 07:41:13 -07001829 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001830
1831}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001832
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001833void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1834 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001835 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001836 if (outer.isEmpty()) {
1837 return;
1838 }
1839 if (inner.isEmpty()) {
1840 this->drawRRect(outer, paint);
1841 return;
1842 }
1843
1844 // We don't have this method (yet), but technically this is what we should
1845 // be able to assert...
1846 // SkASSERT(outer.contains(inner));
1847 //
1848 // For now at least check for containment of bounds
1849 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1850
1851 this->onDrawDRRect(outer, inner, paint);
1852}
1853
reed41af9662015-01-05 07:49:08 -08001854// These need to stop being virtual -- clients need to override the onDraw... versions
1855
1856void SkCanvas::drawPaint(const SkPaint& paint) {
1857 this->onDrawPaint(paint);
1858}
1859
1860void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1861 this->onDrawRect(r, paint);
1862}
1863
1864void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1865 this->onDrawOval(r, paint);
1866}
1867
1868void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1869 this->onDrawRRect(rrect, paint);
1870}
1871
1872void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1873 this->onDrawPoints(mode, count, pts, paint);
1874}
1875
1876void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1877 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1878 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1879 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1880 indices, indexCount, paint);
1881}
1882
1883void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1884 this->onDrawPath(path, paint);
1885}
1886
reeda85d4d02015-05-06 12:56:48 -07001887void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001888 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001889 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001890}
1891
reede47829b2015-08-06 10:02:53 -07001892void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1893 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001894 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001895 if (dst.isEmpty() || src.isEmpty()) {
1896 return;
1897 }
1898 this->onDrawImageRect(image, &src, dst, paint, constraint);
1899}
reed41af9662015-01-05 07:49:08 -08001900
reed84984ef2015-07-17 07:09:43 -07001901void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1902 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001903 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001904 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001905}
1906
reede47829b2015-08-06 10:02:53 -07001907void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1908 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001909 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001910 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1911 constraint);
1912}
reede47829b2015-08-06 10:02:53 -07001913
reed4c21dc52015-06-25 12:32:03 -07001914void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1915 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001916 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001917 if (dst.isEmpty()) {
1918 return;
1919 }
1920 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001921 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001922 }
1923 this->onDrawImageNine(image, center, dst, paint);
1924}
1925
reed41af9662015-01-05 07:49:08 -08001926void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001927 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001928 return;
1929 }
reed41af9662015-01-05 07:49:08 -08001930 this->onDrawBitmap(bitmap, dx, dy, paint);
1931}
1932
reede47829b2015-08-06 10:02:53 -07001933void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001934 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001935 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001936 return;
1937 }
reede47829b2015-08-06 10:02:53 -07001938 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001939}
1940
reed84984ef2015-07-17 07:09:43 -07001941void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1942 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001943 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001944}
1945
reede47829b2015-08-06 10:02:53 -07001946void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1947 SrcRectConstraint constraint) {
1948 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1949 constraint);
1950}
reede47829b2015-08-06 10:02:53 -07001951
reed41af9662015-01-05 07:49:08 -08001952void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1953 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001954 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001955 return;
1956 }
reed4c21dc52015-06-25 12:32:03 -07001957 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001958 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001959 }
reed41af9662015-01-05 07:49:08 -08001960 this->onDrawBitmapNine(bitmap, center, dst, paint);
1961}
1962
reed71c3c762015-06-24 10:29:17 -07001963void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1964 const SkColor colors[], int count, SkXfermode::Mode mode,
1965 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001966 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001967 if (count <= 0) {
1968 return;
1969 }
1970 SkASSERT(atlas);
1971 SkASSERT(xform);
1972 SkASSERT(tex);
1973 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1974}
1975
reedf70b5312016-03-04 16:36:20 -08001976void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1977 if (key) {
1978 this->onDrawAnnotation(rect, key, value);
1979 }
1980}
1981
reede47829b2015-08-06 10:02:53 -07001982void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1983 const SkPaint* paint, SrcRectConstraint constraint) {
1984 if (src) {
1985 this->drawImageRect(image, *src, dst, paint, constraint);
1986 } else {
1987 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1988 dst, paint, constraint);
1989 }
1990}
1991void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1992 const SkPaint* paint, SrcRectConstraint constraint) {
1993 if (src) {
1994 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1995 } else {
1996 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1997 dst, paint, constraint);
1998 }
1999}
2000
reed@android.com8a1c16f2008-12-17 15:59:43 +00002001//////////////////////////////////////////////////////////////////////////////
2002// These are the virtual drawing methods
2003//////////////////////////////////////////////////////////////////////////////
2004
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002005void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002006 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002007 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2008 }
2009}
2010
reed41af9662015-01-05 07:49:08 -08002011void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002012 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002013 this->internalDrawPaint(paint);
2014}
2015
2016void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002017 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018
2019 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002020 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002021 }
2022
reed@google.com4e2b3d32011-04-07 14:18:59 +00002023 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002024}
2025
reed41af9662015-01-05 07:49:08 -08002026void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2027 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002028 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002029 if ((long)count <= 0) {
2030 return;
2031 }
2032
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002033 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002034 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002035 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002036 // special-case 2 points (common for drawing a single line)
2037 if (2 == count) {
2038 r.set(pts[0], pts[1]);
2039 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002040 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002041 }
senorblanco87e066e2015-10-28 11:23:36 -07002042 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2043 return;
2044 }
2045 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002046 }
reed@google.coma584aed2012-05-16 14:06:02 +00002047
halcanary96fcdcc2015-08-27 07:41:13 -07002048 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002049
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002050 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002051
reed@android.com8a1c16f2008-12-17 15:59:43 +00002052 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002053 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002054 }
reed@google.com4b226022011-01-11 18:32:13 +00002055
reed@google.com4e2b3d32011-04-07 14:18:59 +00002056 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002057}
2058
reed41af9662015-01-05 07:49:08 -08002059void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002060 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002061 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002062 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002063 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002064 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2065 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2066 SkRect tmp(r);
2067 tmp.sort();
2068
senorblanco87e066e2015-10-28 11:23:36 -07002069 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2070 return;
2071 }
2072 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002073 }
reed@google.com4b226022011-01-11 18:32:13 +00002074
reedc83a2972015-07-16 07:40:45 -07002075 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002076
2077 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002078 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002079 }
2080
reed@google.com4e2b3d32011-04-07 14:18:59 +00002081 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082}
2083
reed41af9662015-01-05 07:49:08 -08002084void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002085 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002086 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002087 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002088 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002089 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2090 return;
2091 }
2092 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002093 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002094
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002095 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002096
2097 while (iter.next()) {
2098 iter.fDevice->drawOval(iter, oval, looper.paint());
2099 }
2100
2101 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002102}
2103
reed41af9662015-01-05 07:49:08 -08002104void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002105 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002106 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002107 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002108 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002109 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2110 return;
2111 }
2112 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002113 }
2114
2115 if (rrect.isRect()) {
2116 // call the non-virtual version
2117 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002118 return;
2119 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002120 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002121 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2122 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002123 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002124
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002125 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002126
2127 while (iter.next()) {
2128 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2129 }
2130
2131 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002132}
2133
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002134void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2135 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002136 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002137 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002138 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002139 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2140 return;
2141 }
2142 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002143 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002144
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002145 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002146
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002147 while (iter.next()) {
2148 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2149 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002150
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002151 LOOPER_END
2152}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002153
reed41af9662015-01-05 07:49:08 -08002154void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002155 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002156 if (!path.isFinite()) {
2157 return;
2158 }
2159
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002160 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002161 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002162 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002163 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002164 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2165 return;
2166 }
2167 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002168 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002169
2170 const SkRect& r = path.getBounds();
2171 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002172 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002173 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002174 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002175 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002176 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002177
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002178 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002179
2180 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002181 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002182 }
2183
reed@google.com4e2b3d32011-04-07 14:18:59 +00002184 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002185}
2186
reed262a71b2015-12-05 13:07:27 -08002187bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002188 if (!paint.getImageFilter()) {
2189 return false;
2190 }
2191
2192 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002193 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002194 return false;
2195 }
2196
2197 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2198 // Once we can filter and the filter will return a result larger than itself, we should be
2199 // able to remove this constraint.
2200 // skbug.com/4526
2201 //
2202 SkPoint pt;
2203 ctm.mapXY(x, y, &pt);
2204 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2205 return ir.contains(fMCRec->fRasterClip.getBounds());
2206}
2207
reeda85d4d02015-05-06 12:56:48 -07002208void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002209 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002210 SkRect bounds = SkRect::MakeXYWH(x, y,
2211 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002212 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002213 SkRect tmp = bounds;
2214 if (paint) {
2215 paint->computeFastBounds(tmp, &tmp);
2216 }
2217 if (this->quickReject(tmp)) {
2218 return;
2219 }
reeda85d4d02015-05-06 12:56:48 -07002220 }
2221
2222 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002223 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002224 paint = lazy.init();
2225 }
reed262a71b2015-12-05 13:07:27 -08002226
reed129ed1c2016-02-22 06:42:31 -08002227 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2228 *paint);
2229 if (drawAsSprite && paint->getImageFilter()) {
2230 SkBitmap bitmap;
2231 if (!as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2232 drawAsSprite = false;
2233 } else{
2234 // Until imagefilters are updated, they cannot handle any src type but N32...
2235 if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) {
2236 drawAsSprite = false;
2237 }
2238 }
2239 }
2240
reed262a71b2015-12-05 13:07:27 -08002241 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2242
reeda85d4d02015-05-06 12:56:48 -07002243 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002244 const SkPaint& pnt = looper.paint();
2245 if (drawAsSprite && pnt.getImageFilter()) {
2246 SkBitmap bitmap;
2247 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2248 SkPoint pt;
2249 iter.fMatrix->mapXY(x, y, &pt);
2250 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2251 SkScalarRoundToInt(pt.fX),
2252 SkScalarRoundToInt(pt.fY), pnt);
2253 }
2254 } else {
2255 iter.fDevice->drawImage(iter, image, x, y, pnt);
2256 }
reeda85d4d02015-05-06 12:56:48 -07002257 }
2258
2259 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002260}
2261
reed41af9662015-01-05 07:49:08 -08002262void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002263 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002264 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002265 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002266 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002267 if (paint) {
2268 paint->computeFastBounds(dst, &storage);
2269 }
2270 if (this->quickReject(storage)) {
2271 return;
2272 }
reeda85d4d02015-05-06 12:56:48 -07002273 }
2274 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002275 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002276 paint = lazy.init();
2277 }
2278
senorblancoc41e7e12015-12-07 12:51:30 -08002279 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002280 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002281
2282 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002283 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002284 }
2285
2286 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002287}
2288
reed41af9662015-01-05 07:49:08 -08002289void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002290 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002291 SkDEBUGCODE(bitmap.validate();)
2292
reed33366972015-10-08 09:22:02 -07002293 if (bitmap.drawsNothing()) {
2294 return;
2295 }
2296
2297 SkLazyPaint lazy;
2298 if (nullptr == paint) {
2299 paint = lazy.init();
2300 }
2301
2302 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2303
2304 SkRect storage;
2305 const SkRect* bounds = nullptr;
2306 if (paint->canComputeFastBounds()) {
2307 bitmap.getBounds(&storage);
2308 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002309 SkRect tmp = storage;
2310 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2311 return;
2312 }
2313 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002314 }
reed@google.com4b226022011-01-11 18:32:13 +00002315
reed129ed1c2016-02-22 06:42:31 -08002316 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2317 *paint);
2318 if (drawAsSprite && paint->getImageFilter()) {
2319 // Until imagefilters are updated, they cannot handle any src type but N32...
2320 if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) {
2321 drawAsSprite = false;
2322 }
2323 }
2324
reed262a71b2015-12-05 13:07:27 -08002325 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002326
2327 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002328 const SkPaint& pnt = looper.paint();
2329 if (drawAsSprite && pnt.getImageFilter()) {
2330 SkPoint pt;
2331 iter.fMatrix->mapXY(x, y, &pt);
2332 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2333 SkScalarRoundToInt(pt.fX),
2334 SkScalarRoundToInt(pt.fY), pnt);
2335 } else {
2336 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2337 }
reed33366972015-10-08 09:22:02 -07002338 }
reed262a71b2015-12-05 13:07:27 -08002339
reed33366972015-10-08 09:22:02 -07002340 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002341}
2342
reed@google.com9987ec32011-09-07 11:57:52 +00002343// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002344void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002345 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002346 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002347 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002348 return;
2349 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002350
halcanary96fcdcc2015-08-27 07:41:13 -07002351 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002352 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002353 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2354 return;
2355 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002356 }
reed@google.com3d608122011-11-21 15:16:16 +00002357
reed@google.com33535f32012-09-25 15:37:50 +00002358 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002359 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002360 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002361 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002362
senorblancoc41e7e12015-12-07 12:51:30 -08002363 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002364 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002365
reed@google.com33535f32012-09-25 15:37:50 +00002366 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002367 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002368 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002369
reed@google.com33535f32012-09-25 15:37:50 +00002370 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002371}
2372
reed41af9662015-01-05 07:49:08 -08002373void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002374 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002375 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002376 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002377 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002378}
2379
reed4c21dc52015-06-25 12:32:03 -07002380void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2381 const SkPaint* paint) {
2382 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2383
halcanary96fcdcc2015-08-27 07:41:13 -07002384 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002385 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002386 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2387 return;
2388 }
reed@google.com3d608122011-11-21 15:16:16 +00002389 }
reed4c21dc52015-06-25 12:32:03 -07002390
2391 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002392 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002393 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002394 }
reed4c21dc52015-06-25 12:32:03 -07002395
senorblancoc41e7e12015-12-07 12:51:30 -08002396 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002397
2398 while (iter.next()) {
2399 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002400 }
reed4c21dc52015-06-25 12:32:03 -07002401
2402 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002403}
2404
reed41af9662015-01-05 07:49:08 -08002405void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2406 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002407 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002408 SkDEBUGCODE(bitmap.validate();)
2409
halcanary96fcdcc2015-08-27 07:41:13 -07002410 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002411 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002412 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2413 return;
2414 }
reed4c21dc52015-06-25 12:32:03 -07002415 }
2416
2417 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002418 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002419 paint = lazy.init();
2420 }
2421
senorblancoc41e7e12015-12-07 12:51:30 -08002422 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002423
2424 while (iter.next()) {
2425 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2426 }
2427
2428 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002429}
2430
reed@google.comf67e4cf2011-03-15 20:56:58 +00002431class SkDeviceFilteredPaint {
2432public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002433 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002434 uint32_t filteredFlags = device->filterTextFlags(paint);
2435 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002436 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002437 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002438 fPaint = newPaint;
2439 } else {
2440 fPaint = &paint;
2441 }
2442 }
2443
reed@google.comf67e4cf2011-03-15 20:56:58 +00002444 const SkPaint& paint() const { return *fPaint; }
2445
2446private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002447 const SkPaint* fPaint;
2448 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002449};
2450
bungeman@google.com52c748b2011-08-22 21:30:43 +00002451void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2452 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002453 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002454 draw.fDevice->drawRect(draw, r, paint);
2455 } else {
2456 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002457 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002458 draw.fDevice->drawRect(draw, r, p);
2459 }
2460}
2461
2462void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2463 const char text[], size_t byteLength,
2464 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002465 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002466
2467 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002468 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002469 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002470 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002471 return;
2472 }
2473
2474 SkScalar width = 0;
2475 SkPoint start;
2476
2477 start.set(0, 0); // to avoid warning
2478 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2479 SkPaint::kStrikeThruText_Flag)) {
2480 width = paint.measureText(text, byteLength);
2481
2482 SkScalar offsetX = 0;
2483 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2484 offsetX = SkScalarHalf(width);
2485 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2486 offsetX = width;
2487 }
2488 start.set(x - offsetX, y);
2489 }
2490
2491 if (0 == width) {
2492 return;
2493 }
2494
2495 uint32_t flags = paint.getFlags();
2496
2497 if (flags & (SkPaint::kUnderlineText_Flag |
2498 SkPaint::kStrikeThruText_Flag)) {
2499 SkScalar textSize = paint.getTextSize();
2500 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2501 SkRect r;
2502
2503 r.fLeft = start.fX;
2504 r.fRight = start.fX + width;
2505
2506 if (flags & SkPaint::kUnderlineText_Flag) {
2507 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2508 start.fY);
2509 r.fTop = offset;
2510 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002511 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002512 }
2513 if (flags & SkPaint::kStrikeThruText_Flag) {
2514 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2515 start.fY);
2516 r.fTop = offset;
2517 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002518 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002519 }
2520 }
2521}
2522
reed@google.come0d9ce82014-04-23 04:00:17 +00002523void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2524 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002525 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002526
2527 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002528 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002529 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002530 DrawTextDecorations(iter, dfp.paint(),
2531 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002532 }
2533
reed@google.com4e2b3d32011-04-07 14:18:59 +00002534 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002535}
2536
reed@google.come0d9ce82014-04-23 04:00:17 +00002537void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2538 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002539 SkPoint textOffset = SkPoint::Make(0, 0);
2540
halcanary96fcdcc2015-08-27 07:41:13 -07002541 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002542
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002544 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002545 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002546 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002547 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002548
reed@google.com4e2b3d32011-04-07 14:18:59 +00002549 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002550}
2551
reed@google.come0d9ce82014-04-23 04:00:17 +00002552void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2553 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002554
2555 SkPoint textOffset = SkPoint::Make(0, constY);
2556
halcanary96fcdcc2015-08-27 07:41:13 -07002557 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002558
reed@android.com8a1c16f2008-12-17 15:59:43 +00002559 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002560 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002561 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002562 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002563 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002564
reed@google.com4e2b3d32011-04-07 14:18:59 +00002565 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002566}
2567
reed@google.come0d9ce82014-04-23 04:00:17 +00002568void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2569 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002570 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002571
reed@android.com8a1c16f2008-12-17 15:59:43 +00002572 while (iter.next()) {
2573 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002574 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002575 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002576
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002577 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002578}
2579
fmalita00d5c2c2014-08-21 08:53:26 -07002580void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2581 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002582
fmalita85d5eb92015-03-04 11:20:12 -08002583 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002584 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002585 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002586 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002587 SkRect tmp;
2588 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2589 return;
2590 }
2591 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002592 }
2593
fmalita024f9962015-03-03 19:08:17 -08002594 // We cannot filter in the looper as we normally do, because the paint is
2595 // incomplete at this point (text-related attributes are embedded within blob run paints).
2596 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002597 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002598
fmalita85d5eb92015-03-04 11:20:12 -08002599 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002600
fmalitaaa1b9122014-08-28 14:32:24 -07002601 while (iter.next()) {
2602 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002603 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002604 }
2605
fmalitaaa1b9122014-08-28 14:32:24 -07002606 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002607
2608 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002609}
2610
reed@google.come0d9ce82014-04-23 04:00:17 +00002611// These will become non-virtual, so they always call the (virtual) onDraw... method
2612void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2613 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002614 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002615 this->onDrawText(text, byteLength, x, y, paint);
2616}
2617void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2618 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002619 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002620 this->onDrawPosText(text, byteLength, pos, paint);
2621}
2622void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2623 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002624 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002625 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2626}
2627void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2628 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002629 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002630 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2631}
fmalita00d5c2c2014-08-21 08:53:26 -07002632void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2633 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002634 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002635 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002636 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002637}
reed@google.come0d9ce82014-04-23 04:00:17 +00002638
reed41af9662015-01-05 07:49:08 -08002639void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2640 const SkPoint verts[], const SkPoint texs[],
2641 const SkColor colors[], SkXfermode* xmode,
2642 const uint16_t indices[], int indexCount,
2643 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002644 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002645 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002646
reed@android.com8a1c16f2008-12-17 15:59:43 +00002647 while (iter.next()) {
2648 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002649 colors, xmode, indices, indexCount,
2650 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002651 }
reed@google.com4b226022011-01-11 18:32:13 +00002652
reed@google.com4e2b3d32011-04-07 14:18:59 +00002653 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002654}
2655
dandovb3c9d1c2014-08-12 08:34:29 -07002656void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2657 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002658 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002659 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002660 return;
2661 }
mtklein6cfa73a2014-08-13 13:33:49 -07002662
dandovecfff212014-08-04 10:02:00 -07002663 // Since a patch is always within the convex hull of the control points, we discard it when its
2664 // bounding rectangle is completely outside the current clip.
2665 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002666 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002667 if (this->quickReject(bounds)) {
2668 return;
2669 }
mtklein6cfa73a2014-08-13 13:33:49 -07002670
dandovb3c9d1c2014-08-12 08:34:29 -07002671 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2672}
2673
2674void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2675 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2676
halcanary96fcdcc2015-08-27 07:41:13 -07002677 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002678
dandovecfff212014-08-04 10:02:00 -07002679 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002680 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002681 }
mtklein6cfa73a2014-08-13 13:33:49 -07002682
dandovecfff212014-08-04 10:02:00 -07002683 LOOPER_END
2684}
2685
reeda8db7282015-07-07 10:22:31 -07002686void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002687 RETURN_ON_NULL(dr);
2688 if (x || y) {
2689 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2690 this->onDrawDrawable(dr, &matrix);
2691 } else {
2692 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002693 }
2694}
2695
reeda8db7282015-07-07 10:22:31 -07002696void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002697 RETURN_ON_NULL(dr);
2698 if (matrix && matrix->isIdentity()) {
2699 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002700 }
reede3b38ce2016-01-08 09:18:44 -08002701 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002702}
2703
2704void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2705 SkRect bounds = dr->getBounds();
2706 if (matrix) {
2707 matrix->mapRect(&bounds);
2708 }
2709 if (this->quickReject(bounds)) {
2710 return;
2711 }
2712 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002713}
2714
reed71c3c762015-06-24 10:29:17 -07002715void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2716 const SkColor colors[], int count, SkXfermode::Mode mode,
2717 const SkRect* cull, const SkPaint* paint) {
2718 if (cull && this->quickReject(*cull)) {
2719 return;
2720 }
2721
2722 SkPaint pnt;
2723 if (paint) {
2724 pnt = *paint;
2725 }
2726
halcanary96fcdcc2015-08-27 07:41:13 -07002727 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002728 while (iter.next()) {
2729 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2730 }
2731 LOOPER_END
2732}
2733
reedf70b5312016-03-04 16:36:20 -08002734void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2735 SkASSERT(key);
2736
2737 SkPaint paint;
2738 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2739 while (iter.next()) {
2740 iter.fDevice->drawAnnotation(iter, rect, key, value);
2741 }
2742 LOOPER_END
2743}
2744
reed@android.com8a1c16f2008-12-17 15:59:43 +00002745//////////////////////////////////////////////////////////////////////////////
2746// These methods are NOT virtual, and therefore must call back into virtual
2747// methods, rather than actually drawing themselves.
2748//////////////////////////////////////////////////////////////////////////////
2749
2750void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002751 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002752 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753 SkPaint paint;
2754
2755 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002756 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002757 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758 }
2759 this->drawPaint(paint);
2760}
2761
reed@android.com845fdac2009-06-23 03:01:32 +00002762void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002763 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764 SkPaint paint;
2765
2766 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002767 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002768 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769 }
2770 this->drawPaint(paint);
2771}
2772
2773void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002774 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002776
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777 pt.set(x, y);
2778 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2779}
2780
2781void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002782 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783 SkPoint pt;
2784 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002785
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 pt.set(x, y);
2787 paint.setColor(color);
2788 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2789}
2790
2791void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2792 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002795
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796 pts[0].set(x0, y0);
2797 pts[1].set(x1, y1);
2798 this->drawPoints(kLines_PointMode, 2, pts, paint);
2799}
2800
2801void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2802 SkScalar right, SkScalar bottom,
2803 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002804 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805 SkRect r;
2806
2807 r.set(left, top, right, bottom);
2808 this->drawRect(r, paint);
2809}
2810
2811void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2812 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002813 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814 if (radius < 0) {
2815 radius = 0;
2816 }
2817
2818 SkRect r;
2819 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002820 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002821}
2822
2823void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2824 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002825 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826 if (rx > 0 && ry > 0) {
2827 if (paint.canComputeFastBounds()) {
2828 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002829 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830 return;
2831 }
2832 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002833 SkRRect rrect;
2834 rrect.setRectXY(r, rx, ry);
2835 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002836 } else {
2837 this->drawRect(r, paint);
2838 }
2839}
2840
reed@android.com8a1c16f2008-12-17 15:59:43 +00002841void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2842 SkScalar sweepAngle, bool useCenter,
2843 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002844 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002845 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2846 this->drawOval(oval, paint);
2847 } else {
2848 SkPath path;
2849 if (useCenter) {
2850 path.moveTo(oval.centerX(), oval.centerY());
2851 }
2852 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2853 if (useCenter) {
2854 path.close();
2855 }
2856 this->drawPath(path, paint);
2857 }
2858}
2859
2860void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2861 const SkPath& path, SkScalar hOffset,
2862 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002863 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002864 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002865
reed@android.com8a1c16f2008-12-17 15:59:43 +00002866 matrix.setTranslate(hOffset, vOffset);
2867 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2868}
2869
reed@android.comf76bacf2009-05-13 14:00:33 +00002870///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002871
2872/**
2873 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2874 * against the playback cost of recursing into the subpicture to get at its actual ops.
2875 *
2876 * For now we pick a conservatively small value, though measurement (and other heuristics like
2877 * the type of ops contained) may justify changing this value.
2878 */
2879#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002880
reedd5fa1a42014-08-09 11:08:05 -07002881void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002882 RETURN_ON_NULL(picture);
2883
reed1c2c4412015-04-30 13:09:24 -07002884 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002885 if (matrix && matrix->isIdentity()) {
2886 matrix = nullptr;
2887 }
2888 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2889 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2890 picture->playback(this);
2891 } else {
2892 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002893 }
2894}
robertphillips9b14f262014-06-04 05:40:44 -07002895
reedd5fa1a42014-08-09 11:08:05 -07002896void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2897 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002898 if (!paint || paint->canComputeFastBounds()) {
2899 SkRect bounds = picture->cullRect();
2900 if (paint) {
2901 paint->computeFastBounds(bounds, &bounds);
2902 }
2903 if (matrix) {
2904 matrix->mapRect(&bounds);
2905 }
2906 if (this->quickReject(bounds)) {
2907 return;
2908 }
2909 }
2910
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002911 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002912 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002913 // Canvas has to first give the device the opportunity to render
2914 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002915 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002916 return; // the device has rendered the entire picture
2917 }
2918 }
2919
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002920 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002921 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002922}
2923
reed@android.com8a1c16f2008-12-17 15:59:43 +00002924///////////////////////////////////////////////////////////////////////////////
2925///////////////////////////////////////////////////////////////////////////////
2926
2927SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002928 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002929
2930 SkASSERT(canvas);
2931
2932 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2933 fDone = !fImpl->next();
2934}
2935
2936SkCanvas::LayerIter::~LayerIter() {
2937 fImpl->~SkDrawIter();
2938}
2939
2940void SkCanvas::LayerIter::next() {
2941 fDone = !fImpl->next();
2942}
2943
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002944SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002945 return fImpl->getDevice();
2946}
2947
2948const SkMatrix& SkCanvas::LayerIter::matrix() const {
2949 return fImpl->getMatrix();
2950}
2951
2952const SkPaint& SkCanvas::LayerIter::paint() const {
2953 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002954 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002955 paint = &fDefaultPaint;
2956 }
2957 return *paint;
2958}
2959
2960const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2961int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2962int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002963
2964///////////////////////////////////////////////////////////////////////////////
2965
fmalitac3b589a2014-06-05 12:40:07 -07002966SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002967
2968///////////////////////////////////////////////////////////////////////////////
2969
2970static bool supported_for_raster_canvas(const SkImageInfo& info) {
2971 switch (info.alphaType()) {
2972 case kPremul_SkAlphaType:
2973 case kOpaque_SkAlphaType:
2974 break;
2975 default:
2976 return false;
2977 }
2978
2979 switch (info.colorType()) {
2980 case kAlpha_8_SkColorType:
2981 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002982 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002983 break;
2984 default:
2985 return false;
2986 }
2987
2988 return true;
2989}
2990
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002991SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2992 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002993 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002994 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002995
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002996 SkBitmap bitmap;
2997 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002998 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002999 }
halcanary385fe4d2015-08-26 13:07:48 -07003000 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003001}
reedd5fa1a42014-08-09 11:08:05 -07003002
3003///////////////////////////////////////////////////////////////////////////////
3004
3005SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003006 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003007 : fCanvas(canvas)
3008 , fSaveCount(canvas->getSaveCount())
3009{
bsalomon49f085d2014-09-05 13:34:00 -07003010 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003011 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003012 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003013 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003014 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003015 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003016 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003017 canvas->save();
3018 }
mtklein6cfa73a2014-08-13 13:33:49 -07003019
bsalomon49f085d2014-09-05 13:34:00 -07003020 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003021 canvas->concat(*matrix);
3022 }
3023}
3024
3025SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3026 fCanvas->restoreToCount(fSaveCount);
3027}