blob: d60e0e921158aba69704084530de0802ceea0a88 [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"
robertphillips4418dba2016-03-07 12:45:14 -080031#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000032#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070033#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000034#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000035#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080036#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070037
38#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000039
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000040#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080041#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000042#include "GrRenderTarget.h"
robertphillips7354a4b2015-12-16 05:08:27 -080043#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#endif
45
reede3b38ce2016-01-08 09:18:44 -080046#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
47
reedc83a2972015-07-16 07:40:45 -070048/*
49 * Return true if the drawing this rect would hit every pixels in the canvas.
50 *
51 * Returns false if
52 * - rect does not contain the canvas' bounds
53 * - paint is not fill
54 * - paint would blur or otherwise change the coverage of the rect
55 */
56bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
57 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070058 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
59 (int)kNone_ShaderOverrideOpacity,
60 "need_matching_enums0");
61 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
62 (int)kOpaque_ShaderOverrideOpacity,
63 "need_matching_enums1");
64 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
65 (int)kNotOpaque_ShaderOverrideOpacity,
66 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070067
68 const SkISize size = this->getBaseLayerSize();
69 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
70 if (!this->getClipStack()->quickContains(bounds)) {
71 return false;
72 }
73
74 if (rect) {
75 if (!this->getTotalMatrix().rectStaysRect()) {
76 return false; // conservative
77 }
78
79 SkRect devRect;
80 this->getTotalMatrix().mapRect(&devRect, *rect);
fmalita8c0144c2015-07-22 05:56:16 -070081 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070082 return false;
83 }
84 }
85
86 if (paint) {
87 SkPaint::Style paintStyle = paint->getStyle();
88 if (!(paintStyle == SkPaint::kFill_Style ||
89 paintStyle == SkPaint::kStrokeAndFill_Style)) {
90 return false;
91 }
92 if (paint->getMaskFilter() || paint->getLooper()
93 || paint->getPathEffect() || paint->getImageFilter()) {
94 return false; // conservative
95 }
96 }
97 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
98}
99
100///////////////////////////////////////////////////////////////////////////////////////////////////
101
reedd990e2f2014-12-22 11:58:30 -0800102static bool gIgnoreSaveLayerBounds;
103void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
104 gIgnoreSaveLayerBounds = ignore;
105}
106bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
107 return gIgnoreSaveLayerBounds;
108}
109
reed0acf1b42014-12-22 16:12:38 -0800110static bool gTreatSpriteAsBitmap;
111void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
112 gTreatSpriteAsBitmap = spriteAsBitmap;
113}
114bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
115 return gTreatSpriteAsBitmap;
116}
117
reed@google.comda17f752012-08-16 18:27:05 +0000118// experimental for faster tiled drawing...
119//#define SK_ENABLE_CLIP_QUICKREJECT
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120//#define SK_TRACE_SAVERESTORE
121
122#ifdef SK_TRACE_SAVERESTORE
123 static int gLayerCounter;
124 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
125 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
126
127 static int gRecCounter;
128 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
129 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
130
131 static int gCanvasCounter;
132 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
133 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
134#else
135 #define inc_layer()
136 #define dec_layer()
137 #define inc_rec()
138 #define dec_rec()
139 #define inc_canvas()
140 #define dec_canvas()
141#endif
142
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000143typedef SkTLazy<SkPaint> SkLazyPaint;
144
reedc83a2972015-07-16 07:40:45 -0700145void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000146 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700147 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
148 ? SkSurface::kDiscard_ContentChangeMode
149 : SkSurface::kRetain_ContentChangeMode);
150 }
151}
152
153void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
154 ShaderOverrideOpacity overrideOpacity) {
155 if (fSurfaceBase) {
156 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
157 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
158 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
159 // and therefore we don't care which mode we're in.
160 //
161 if (fSurfaceBase->outstandingImageSnapshot()) {
162 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
163 mode = SkSurface::kDiscard_ContentChangeMode;
164 }
165 }
166 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000167 }
168}
169
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171
reed4a8126e2014-09-22 07:29:03 -0700172static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
173 const uint32_t propFlags = props.flags();
174 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
175 flags &= ~SkPaint::kDither_Flag;
176 }
177 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
178 flags &= ~SkPaint::kAntiAlias_Flag;
179 }
180 return flags;
181}
182
183///////////////////////////////////////////////////////////////////////////////
184
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000185/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 The clip/matrix/proc are fields that reflect the top of the save/restore
187 stack. Whenever the canvas changes, it marks a dirty flag, and then before
188 these are used (assuming we're not on a layer) we rebuild these cache
189 values: they reflect the top of the save stack, but translated and clipped
190 by the device's XY offset and bitmap-bounds.
191*/
192struct DeviceCM {
193 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000194 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000195 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000196 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700197 const SkMatrix* fMatrix;
198 SkMatrix fMatrixStorage;
199 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200
reed96e657d2015-03-10 17:30:07 -0700201 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed86a17e72015-05-14 12:25:22 -0700202 bool conservativeRasterClip, bool deviceIsBitmapDevice)
halcanary96fcdcc2015-08-27 07:41:13 -0700203 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700204 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700205 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700206 {
halcanary96fcdcc2015-08-27 07:41:13 -0700207 if (nullptr != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000209 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 }
reed@google.com4b226022011-01-11 18:32:13 +0000211 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700212 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000213 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000215 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700216 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000217 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 fDevice->unref();
219 }
halcanary385fe4d2015-08-26 13:07:48 -0700220 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000221 }
reed@google.com4b226022011-01-11 18:32:13 +0000222
mtkleinfeaadee2015-04-08 11:25:48 -0700223 void reset(const SkIRect& bounds) {
224 SkASSERT(!fPaint);
225 SkASSERT(!fNext);
226 SkASSERT(fDevice);
227 fClip.setRect(bounds);
228 }
229
reed@google.com045e62d2011-10-24 12:19:46 +0000230 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
231 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000232 int x = fDevice->getOrigin().x();
233 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 int width = fDevice->width();
235 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000236
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 if ((x | y) == 0) {
238 fMatrix = &totalMatrix;
239 fClip = totalClip;
240 } else {
241 fMatrixStorage = totalMatrix;
242 fMatrixStorage.postTranslate(SkIntToScalar(-x),
243 SkIntToScalar(-y));
244 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 totalClip.translate(-x, -y, &fClip);
247 }
248
reed@google.com045e62d2011-10-24 12:19:46 +0000249 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250
251 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000252
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000254 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 SkRegion::kDifference_Op);
256 }
reed@google.com4b226022011-01-11 18:32:13 +0000257
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000258 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
259
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260#ifdef SK_DEBUG
261 if (!fClip.isEmpty()) {
262 SkIRect deviceR;
263 deviceR.set(0, 0, width, height);
264 SkASSERT(deviceR.contains(fClip.getBounds()));
265 }
266#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000267 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268};
269
270/* This is the record we keep for each save/restore level in the stack.
271 Since a level optionally copies the matrix and/or stack, we have pointers
272 for these fields. If the value is copied for this level, the copy is
273 stored in the ...Storage field, and the pointer points to that. If the
274 value is not copied for this level, we ignore ...Storage, and just point
275 at the corresponding value in the previous level in the stack.
276*/
277class SkCanvas::MCRec {
278public:
reed1f836ee2014-07-07 07:49:34 -0700279 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700280 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 /* If there are any layers in the stack, this points to the top-most
282 one that is at or below this level in the stack (so we know what
283 bitmap/device to draw into from this level. This value is NOT
284 reference counted, since the real owner is either our fLayer field,
285 or a previous one in a lower level.)
286 */
reed2ff1fce2014-12-11 07:07:37 -0800287 DeviceCM* fTopLayer;
288 SkRasterClip fRasterClip;
289 SkMatrix fMatrix;
290 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291
reedd9544982014-09-09 18:46:22 -0700292 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700293 fFilter = nullptr;
294 fLayer = nullptr;
295 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800296 fMatrix.reset();
297 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700298
reedd9544982014-09-09 18:46:22 -0700299 // don't bother initializing fNext
300 inc_rec();
301 }
reed2ff1fce2014-12-11 07:07:37 -0800302 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700303 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700304 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700305 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800306 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700307
reed@android.com8a1c16f2008-12-17 15:59:43 +0000308 // don't bother initializing fNext
309 inc_rec();
310 }
311 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000312 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700313 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 dec_rec();
315 }
mtkleinfeaadee2015-04-08 11:25:48 -0700316
317 void reset(const SkIRect& bounds) {
318 SkASSERT(fLayer);
319 SkASSERT(fDeferredSaveCount == 0);
320
321 fMatrix.reset();
322 fRasterClip.setRect(bounds);
323 fLayer->reset(bounds);
324 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325};
326
327class SkDrawIter : public SkDraw {
328public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000329 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000330 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000331 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332 canvas->updateDeviceCMCache();
333
reed687fa1c2015-04-07 08:00:56 -0700334 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000336 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 }
reed@google.com4b226022011-01-11 18:32:13 +0000338
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 bool next() {
340 // skip over recs with empty clips
341 if (fSkipEmptyClips) {
342 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
343 fCurrLayer = fCurrLayer->fNext;
344 }
345 }
346
reed@google.comf68c5e22012-02-24 16:38:58 +0000347 const DeviceCM* rec = fCurrLayer;
348 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349
350 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000351 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
352 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700354 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700355 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700356 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000358 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359
360 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700361 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000362
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 return true;
364 }
365 return false;
366 }
reed@google.com4b226022011-01-11 18:32:13 +0000367
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000368 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000369 int getX() const { return fDevice->getOrigin().x(); }
370 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371 const SkMatrix& getMatrix() const { return *fMatrix; }
372 const SkRegion& getClip() const { return *fClip; }
373 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000374
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375private:
376 SkCanvas* fCanvas;
377 const DeviceCM* fCurrLayer;
378 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 SkBool8 fSkipEmptyClips;
380
381 typedef SkDraw INHERITED;
382};
383
384/////////////////////////////////////////////////////////////////////////////
385
reeddbc3cef2015-04-29 12:18:57 -0700386static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
387 return lazy->isValid() ? lazy->get() : lazy->set(orig);
388}
389
390/**
391 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700392 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700393 */
394static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700395 SkImageFilter* imgf = paint.getImageFilter();
396 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700397 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700398 }
399
400 SkColorFilter* imgCF;
401 if (!imgf->asAColorFilter(&imgCF)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700402 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700403 }
404
405 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700406 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700407 // there is no existing paint colorfilter, so we can just return the imagefilter's
408 return imgCF;
409 }
410
411 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
412 // and we need to combine them into a single colorfilter.
413 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
414 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700415}
416
senorblanco87e066e2015-10-28 11:23:36 -0700417/**
418 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
419 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
420 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
421 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
422 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
423 * conservative "effective" bounds based on the settings in the paint... with one exception. This
424 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
425 * deliberately ignored.
426 */
427static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
428 const SkRect& rawBounds,
429 SkRect* storage) {
430 SkPaint tmpUnfiltered(paint);
431 tmpUnfiltered.setImageFilter(nullptr);
432 if (tmpUnfiltered.canComputeFastBounds()) {
433 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
434 } else {
435 return rawBounds;
436 }
437}
438
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439class AutoDrawLooper {
440public:
senorblanco87e066e2015-10-28 11:23:36 -0700441 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
442 // paint. It's used to determine the size of the offscreen layer for filters.
443 // If null, the clip will be used instead.
reed4a8126e2014-09-22 07:29:03 -0700444 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000445 bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700446 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000447 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800448#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800450#else
451 fFilter = nullptr;
452#endif
reed4a8126e2014-09-22 07:29:03 -0700453 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000454 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700455 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000456 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000457
reeddbc3cef2015-04-29 12:18:57 -0700458 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
459 if (simplifiedCF) {
460 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
461 paint->setColorFilter(simplifiedCF)->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700462 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700463 fPaint = paint;
464 }
465
466 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700467 /**
468 * We implement ImageFilters for a given draw by creating a layer, then applying the
469 * imagefilter to the pixels of that layer (its backing surface/image), and then
470 * we call restore() to xfer that layer to the main canvas.
471 *
472 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
473 * 2. Generate the src pixels:
474 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
475 * return (fPaint). We then draw the primitive (using srcover) into a cleared
476 * buffer/surface.
477 * 3. Restore the layer created in #1
478 * The imagefilter is passed the buffer/surface from the layer (now filled with the
479 * src pixels of the primitive). It returns a new "filtered" buffer, which we
480 * draw onto the previous layer using the xfermode from the original paint.
481 */
reed@google.com8926b162012-03-23 15:36:36 +0000482 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700483 tmp.setImageFilter(fPaint->getImageFilter());
484 tmp.setXfermode(fPaint->getXfermode());
senorblanco87e066e2015-10-28 11:23:36 -0700485 SkRect storage;
486 if (rawBounds) {
487 // Make rawBounds include all paint outsets except for those due to image filters.
488 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
489 }
reedbfd5f172016-01-07 11:28:08 -0800490 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700491 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700492 fTempLayerForImageFilter = true;
493 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000494 }
495
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000496 if (SkDrawLooper* looper = paint.getLooper()) {
497 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
498 looper->contextSize());
499 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000500 fIsSimple = false;
501 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700502 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000503 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700504 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000505 }
piotaixrb5fae932014-09-24 13:03:30 -0700506
reed4a8126e2014-09-22 07:29:03 -0700507 uint32_t oldFlags = paint.getFlags();
508 fNewPaintFlags = filter_paint_flags(props, oldFlags);
509 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700510 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700511 paint->setFlags(fNewPaintFlags);
512 fPaint = paint;
513 // if we're not simple, doNext() will take care of calling setFlags()
514 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000515 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000516
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700518 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000519 fCanvas->internalRestore();
520 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000521 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000522 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000523
reed@google.com4e2b3d32011-04-07 14:18:59 +0000524 const SkPaint& paint() const {
525 SkASSERT(fPaint);
526 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000527 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000528
reed@google.com129ec222012-05-15 13:24:09 +0000529 bool next(SkDrawFilter::Type drawType) {
530 if (fDone) {
531 return false;
532 } else if (fIsSimple) {
533 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000534 return !fPaint->nothingToDraw();
535 } else {
536 return this->doNext(drawType);
537 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000538 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000539
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540private:
reeddbc3cef2015-04-29 12:18:57 -0700541 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
542 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000543 SkCanvas* fCanvas;
544 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000545 SkDrawFilter* fFilter;
546 const SkPaint* fPaint;
547 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700548 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700549 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000550 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000551 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000552 SkDrawLooper::Context* fLooperContext;
553 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000554
555 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556};
557
reed@google.com129ec222012-05-15 13:24:09 +0000558bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700559 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000560 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700561 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000562
reeddbc3cef2015-04-29 12:18:57 -0700563 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
564 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700565 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000566
reed5c476fb2015-04-20 08:04:21 -0700567 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700568 paint->setImageFilter(nullptr);
569 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000570 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000571
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000572 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000573 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000574 return false;
575 }
576 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000577 if (!fFilter->filter(paint, drawType)) {
578 fDone = true;
579 return false;
580 }
halcanary96fcdcc2015-08-27 07:41:13 -0700581 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000582 // no looper means we only draw once
583 fDone = true;
584 }
585 }
586 fPaint = paint;
587
588 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000589 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000590 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000591 }
592
593 // call this after any possible paint modifiers
594 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700595 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000596 return false;
597 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000598 return true;
599}
600
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601////////// macros to place around the internal draw calls //////////////////
602
reed262a71b2015-12-05 13:07:27 -0800603#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
604 this->predrawNotify(); \
605 AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \
606 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
607 SkDrawIter iter(this);
608
609
reed@google.com8926b162012-03-23 15:36:36 +0000610#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000611 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700612 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000613 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000614 SkDrawIter iter(this);
615
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000616#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000617 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700618 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000619 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000620 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000621
reedc83a2972015-07-16 07:40:45 -0700622#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
623 this->predrawNotify(bounds, &paint, auxOpaque); \
624 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
625 while (looper.next(type)) { \
626 SkDrawIter iter(this);
627
reed@google.com4e2b3d32011-04-07 14:18:59 +0000628#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629
630////////////////////////////////////////////////////////////////////////////
631
mtkleinfeaadee2015-04-08 11:25:48 -0700632void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
633 this->restoreToCount(1);
634 fCachedLocalClipBounds.setEmpty();
635 fCachedLocalClipBoundsDirty = true;
636 fClipStack->reset();
637 fMCRec->reset(bounds);
638
639 // We're peering through a lot of structs here. Only at this scope do we
640 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
641 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
642}
643
reedd9544982014-09-09 18:46:22 -0700644SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800645 if (device && device->forceConservativeRasterClip()) {
646 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
647 }
648 // Since init() is only called once by our constructors, it is safe to perform this
649 // const-cast.
650 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
651
reed@google.comc0784db2013-12-13 21:16:12 +0000652 fCachedLocalClipBounds.setEmpty();
653 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000654 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000655 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700656 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800657 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700658 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659
halcanary385fe4d2015-08-26 13:07:48 -0700660 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700661
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700663 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664
reeda499f902015-05-01 09:34:31 -0700665 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
666 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700667 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700668
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670
halcanary96fcdcc2015-08-27 07:41:13 -0700671 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000672
reedf92c8662014-08-18 08:02:43 -0700673 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700674 // The root device and the canvas should always have the same pixel geometry
675 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700676 device->onAttachToCanvas(this);
677 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800678 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700679 }
680 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681}
682
reed@google.comcde92112011-07-06 20:00:52 +0000683SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000684 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700685 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800686 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000687{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000688 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000689
halcanary96fcdcc2015-08-27 07:41:13 -0700690 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000691}
692
reedd9544982014-09-09 18:46:22 -0700693static SkBitmap make_nopixels(int width, int height) {
694 SkBitmap bitmap;
695 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
696 return bitmap;
697}
698
699class SkNoPixelsBitmapDevice : public SkBitmapDevice {
700public:
robertphillipsfcf78292015-06-19 11:49:52 -0700701 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
702 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800703 {
704 this->setOrigin(bounds.x(), bounds.y());
705 }
reedd9544982014-09-09 18:46:22 -0700706
707private:
piotaixrb5fae932014-09-24 13:03:30 -0700708
reedd9544982014-09-09 18:46:22 -0700709 typedef SkBitmapDevice INHERITED;
710};
711
reed96a857e2015-01-25 10:33:58 -0800712SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000713 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800714 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800715 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000716{
717 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700718
halcanary385fe4d2015-08-26 13:07:48 -0700719 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
720 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700721}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000722
reed78e27682014-11-19 08:04:34 -0800723SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700724 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700725 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800726 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700727{
728 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700729
halcanary385fe4d2015-08-26 13:07:48 -0700730 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700731}
732
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000733SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000734 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700735 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800736 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000737{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700739
reedd9544982014-09-09 18:46:22 -0700740 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000741}
742
robertphillipsfcf78292015-06-19 11:49:52 -0700743SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
744 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700745 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800746 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700747{
748 inc_canvas();
749
750 this->init(device, flags);
751}
752
reed4a8126e2014-09-22 07:29:03 -0700753SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700754 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700755 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800756 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700757{
758 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700759
halcanary385fe4d2015-08-26 13:07:48 -0700760 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700761 this->init(device, kDefault_InitFlags);
762}
reed29c857d2014-09-21 10:25:07 -0700763
reed4a8126e2014-09-22 07:29:03 -0700764SkCanvas::SkCanvas(const SkBitmap& bitmap)
765 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
766 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800767 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700768{
769 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700770
halcanary385fe4d2015-08-26 13:07:48 -0700771 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700772 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773}
774
775SkCanvas::~SkCanvas() {
776 // free up the contents of our deque
777 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000778
reed@android.com8a1c16f2008-12-17 15:59:43 +0000779 this->internalRestore(); // restore the last, since we're going away
780
halcanary385fe4d2015-08-26 13:07:48 -0700781 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000782
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783 dec_canvas();
784}
785
fmalita53d9f1c2016-01-25 06:23:54 -0800786#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787SkDrawFilter* SkCanvas::getDrawFilter() const {
788 return fMCRec->fFilter;
789}
790
791SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700792 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000793 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
794 return filter;
795}
fmalita77650002016-01-21 18:47:11 -0800796#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000798SkMetaData& SkCanvas::getMetaData() {
799 // metadata users are rare, so we lazily allocate it. If that changes we
800 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700801 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000802 fMetaData = new SkMetaData;
803 }
804 return *fMetaData;
805}
806
reed@android.com8a1c16f2008-12-17 15:59:43 +0000807///////////////////////////////////////////////////////////////////////////////
808
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000809void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000810 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000811 if (device) {
812 device->flush();
813 }
814}
815
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000816SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000817 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000818 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
819}
820
senorblancoafc7cce2016-02-02 18:44:15 -0800821SkIRect SkCanvas::getTopLayerBounds() const {
822 SkBaseDevice* d = this->getTopDevice();
823 if (!d) {
824 return SkIRect::MakeEmpty();
825 }
826 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
827}
828
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000829SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000831 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000832 SkASSERT(rec && rec->fLayer);
833 return rec->fLayer->fDevice;
834}
835
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000836SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000837 if (updateMatrixClip) {
838 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
839 }
reed@google.com9266fed2011-03-30 00:18:03 +0000840 return fMCRec->fTopLayer->fDevice;
841}
842
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000843bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
844 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
845 return false;
846 }
847
848 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700849 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700850 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000851 return false;
852 }
853 weAllocated = true;
854 }
855
reedcf01e312015-05-23 19:14:51 -0700856 SkAutoPixmapUnlock unlocker;
857 if (bitmap->requestLock(&unlocker)) {
858 const SkPixmap& pm = unlocker.pixmap();
859 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
860 return true;
861 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000862 }
863
864 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700865 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000866 }
867 return false;
868}
reed@google.com51df9e32010-12-23 19:29:18 +0000869
bsalomon@google.comc6980972011-11-02 19:57:21 +0000870bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000871 SkIRect r = srcRect;
872 const SkISize size = this->getBaseLayerSize();
873 if (!r.intersect(0, 0, size.width(), size.height())) {
874 bitmap->reset();
875 return false;
876 }
877
reed84825042014-09-02 12:50:45 -0700878 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000879 // bitmap will already be reset.
880 return false;
881 }
882 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
883 bitmap->reset();
884 return false;
885 }
886 return true;
887}
888
reed96472de2014-12-10 09:53:42 -0800889bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000890 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000891 if (!device) {
892 return false;
893 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000894 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800895
reed96472de2014-12-10 09:53:42 -0800896 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
897 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000898 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000899 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000900
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000901 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800902 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000903}
904
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000905bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
906 if (bitmap.getTexture()) {
907 return false;
908 }
reedcf01e312015-05-23 19:14:51 -0700909
910 SkAutoPixmapUnlock unlocker;
911 if (bitmap.requestLock(&unlocker)) {
912 const SkPixmap& pm = unlocker.pixmap();
913 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000914 }
915 return false;
916}
917
918bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
919 int x, int y) {
920 switch (origInfo.colorType()) {
921 case kUnknown_SkColorType:
922 case kIndex_8_SkColorType:
923 return false;
924 default:
925 break;
926 }
halcanary96fcdcc2015-08-27 07:41:13 -0700927 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000928 return false;
929 }
930
931 const SkISize size = this->getBaseLayerSize();
932 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
933 if (!target.intersect(0, 0, size.width(), size.height())) {
934 return false;
935 }
936
937 SkBaseDevice* device = this->getDevice();
938 if (!device) {
939 return false;
940 }
941
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000942 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700943 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000944
945 // if x or y are negative, then we have to adjust pixels
946 if (x > 0) {
947 x = 0;
948 }
949 if (y > 0) {
950 y = 0;
951 }
952 // here x,y are either 0 or negative
953 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
954
reed4af35f32014-06-27 17:47:49 -0700955 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700956 const bool completeOverwrite = info.dimensions() == size;
957 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700958
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000959 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000960 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000961}
reed@google.com51df9e32010-12-23 19:29:18 +0000962
junov@google.com4370aed2012-01-18 16:21:08 +0000963SkCanvas* SkCanvas::canvasForDrawIter() {
964 return this;
965}
966
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967//////////////////////////////////////////////////////////////////////////////
968
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969void SkCanvas::updateDeviceCMCache() {
970 if (fDeviceCMDirty) {
971 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700972 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000974
halcanary96fcdcc2015-08-27 07:41:13 -0700975 if (nullptr == layer->fNext) { // only one layer
976 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000978 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979 do {
reed687fa1c2015-04-07 08:00:56 -0700980 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700981 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982 }
983 fDeviceCMDirty = false;
984 }
985}
986
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987///////////////////////////////////////////////////////////////////////////////
988
reed2ff1fce2014-12-11 07:07:37 -0800989void SkCanvas::checkForDeferredSave() {
990 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800991 this->doSave();
992 }
993}
994
reedf0090cb2014-11-26 08:55:51 -0800995int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800996#ifdef SK_DEBUG
997 int count = 0;
998 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
999 for (;;) {
1000 const MCRec* rec = (const MCRec*)iter.next();
1001 if (!rec) {
1002 break;
1003 }
1004 count += 1 + rec->fDeferredSaveCount;
1005 }
1006 SkASSERT(count == fSaveCount);
1007#endif
1008 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001009}
1010
1011int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001012 fSaveCount += 1;
1013 fMCRec->fDeferredSaveCount += 1;
1014 return this->getSaveCount() - 1; // return our prev value
1015}
1016
1017void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001018 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001019
1020 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1021 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001022 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001023}
1024
1025void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001026 if (fMCRec->fDeferredSaveCount > 0) {
1027 SkASSERT(fSaveCount > 1);
1028 fSaveCount -= 1;
1029 fMCRec->fDeferredSaveCount -= 1;
1030 } else {
1031 // check for underflow
1032 if (fMCStack.count() > 1) {
1033 this->willRestore();
1034 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001035 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001036 this->internalRestore();
1037 this->didRestore();
1038 }
reedf0090cb2014-11-26 08:55:51 -08001039 }
1040}
1041
1042void SkCanvas::restoreToCount(int count) {
1043 // sanity check
1044 if (count < 1) {
1045 count = 1;
1046 }
mtkleinf0f14112014-12-12 08:46:25 -08001047
reedf0090cb2014-11-26 08:55:51 -08001048 int n = this->getSaveCount() - count;
1049 for (int i = 0; i < n; ++i) {
1050 this->restore();
1051 }
1052}
1053
reed2ff1fce2014-12-11 07:07:37 -08001054void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001056 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001057 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001058
reed687fa1c2015-04-07 08:00:56 -07001059 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001060}
1061
reed4960eee2015-12-18 07:09:18 -08001062bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001063#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001064 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@google.comb93ba452014-03-10 19:47:58 +00001065#else
1066 return true;
1067#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068}
1069
reed4960eee2015-12-18 07:09:18 -08001070bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001071 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001072 SkIRect clipBounds;
1073 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001074 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001075 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001076
reed96e657d2015-03-10 17:30:07 -07001077 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1078
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001079 if (imageFilter) {
reed1d524692016-02-22 05:57:31 -08001080 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblancodb64af32015-12-09 10:11:43 -08001081 if (bounds && !imageFilter->canComputeFastBounds()) {
1082 bounds = nullptr;
1083 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001084 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001085 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001086 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001088
reed96e657d2015-03-10 17:30:07 -07001089 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090 r.roundOut(&ir);
1091 // early exit if the layer's bounds are clipped out
1092 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001093 if (BoundsAffectsClip(saveLayerFlags)) {
reed9b3aa542015-03-11 08:47:12 -07001094 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001095 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001096 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001097 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 }
1099 } else { // no user bounds, so just use the clip
1100 ir = clipBounds;
1101 }
reed180aec42015-03-11 10:39:04 -07001102 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103
reed4960eee2015-12-18 07:09:18 -08001104 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001105 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -07001106 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -07001107 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001108 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001109 }
1110
1111 if (intersection) {
1112 *intersection = ir;
1113 }
1114 return true;
1115}
1116
reed4960eee2015-12-18 07:09:18 -08001117
reed4960eee2015-12-18 07:09:18 -08001118int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1119 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001120}
1121
reed70ee31b2015-12-10 13:44:45 -08001122int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001123 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1124}
1125
1126int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1127 SaveLayerRec rec(origRec);
1128 if (gIgnoreSaveLayerBounds) {
1129 rec.fBounds = nullptr;
1130 }
1131 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1132 fSaveCount += 1;
1133 this->internalSaveLayer(rec, strategy);
1134 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001135}
1136
reedbfd5f172016-01-07 11:28:08 -08001137static void draw_filter_into_device(SkBaseDevice* src, const SkImageFilter* filter,
1138 SkBaseDevice* dst, const SkMatrix& ctm) {
robertphillips7354a4b2015-12-16 05:08:27 -08001139
1140 SkBitmap srcBM;
1141
1142#if SK_SUPPORT_GPU
1143 GrRenderTarget* srcRT = src->accessRenderTarget();
1144 if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) {
1145 // When both the src & the dst are on the gpu but the src doesn't have a texture,
1146 // we create a temporary texture for the draw.
1147 // TODO: we should actually only copy the portion of the source needed to apply the image
1148 // filter
1149 GrContext* context = srcRT->getContext();
bsalomon5ec26ae2016-02-25 08:33:02 -08001150 SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(srcRT->desc(),
1151 SkBudgeted::kYes));
robertphillips7354a4b2015-12-16 05:08:27 -08001152
1153 context->copySurface(tex, srcRT);
1154
1155 GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM);
1156 } else
1157#endif
1158 {
1159 srcBM = src->accessBitmap(false);
1160 }
1161
1162 SkCanvas c(dst);
1163
reedbfd5f172016-01-07 11:28:08 -08001164 SkAutoTUnref<SkImageFilter> localF(filter->newWithLocalMatrix(ctm));
robertphillips7354a4b2015-12-16 05:08:27 -08001165 SkPaint p;
reedbfd5f172016-01-07 11:28:08 -08001166 p.setImageFilter(localF);
1167 const SkScalar x = SkIntToScalar(src->getOrigin().x());
1168 const SkScalar y = SkIntToScalar(src->getOrigin().y());
1169 c.drawBitmap(srcBM, x, y, &p);
robertphillips7354a4b2015-12-16 05:08:27 -08001170}
reed70ee31b2015-12-10 13:44:45 -08001171
reed129ed1c2016-02-22 06:42:31 -08001172static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1173 const SkPaint* paint) {
1174 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1175 // e.g. sRGB or F16, we can remove this check
1176 const bool hasImageFilter = paint && paint->getImageFilter();
1177
1178 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1179 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1180 // force to L32
1181 return SkImageInfo::MakeN32(w, h, alphaType);
1182 } else {
1183 // keep the same characteristics as the prev
1184 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.profileType());
1185 }
1186}
1187
reed4960eee2015-12-18 07:09:18 -08001188void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1189 const SkRect* bounds = rec.fBounds;
1190 const SkPaint* paint = rec.fPaint;
1191 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1192
reed@google.comb93ba452014-03-10 19:47:58 +00001193#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001194 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001195#endif
1196
junov@chromium.orga907ac32012-02-24 21:54:07 +00001197 // do this before we create the layer. We don't call the public save() since
1198 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001199 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001200
1201 fDeviceCMDirty = true;
1202
1203 SkIRect ir;
reed4960eee2015-12-18 07:09:18 -08001204 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001205 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001206 }
1207
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001208 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1209 // the clipRectBounds() call above?
1210 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001211 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001212 }
1213
reed4960eee2015-12-18 07:09:18 -08001214 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001215 SkPixelGeometry geo = fProps.pixelGeometry();
1216 if (paint) {
reed76033be2015-03-14 10:54:31 -07001217 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001218 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001219 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001220 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001221 }
1222 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223
reedb2db8982014-11-13 12:41:02 -08001224 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001225 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001226 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001227 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001228 }
reedb2db8982014-11-13 12:41:02 -08001229
reed129ed1c2016-02-22 06:42:31 -08001230 SkImageInfo info = make_layer_info(device->imageInfo(), ir.width(), ir.height(), isOpaque,
1231 paint);
1232
reed61f501f2015-04-29 08:34:00 -07001233 bool forceSpriteOnRestore = false;
1234 {
reed70ee31b2015-12-10 13:44:45 -08001235 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001236 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001237 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001238 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1239 preserveLCDText, false);
reed61f501f2015-04-29 08:34:00 -07001240 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001241 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001242 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001243 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1244 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001245 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001246 SkErrorInternals::SetError(kInternalError_SkError,
1247 "Unable to create device for layer.");
1248 return;
1249 }
1250 forceSpriteOnRestore = true;
1251 }
1252 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001253 }
reed@google.com6f8f2922011-03-04 22:27:10 +00001254 device->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001255
reedbfd5f172016-01-07 11:28:08 -08001256 if (rec.fBackdrop) {
1257 draw_filter_into_device(fMCRec->fTopLayer->fDevice, rec.fBackdrop, device, fMCRec->fMatrix);
robertphillips7354a4b2015-12-16 05:08:27 -08001258 }
1259
halcanary385fe4d2015-08-26 13:07:48 -07001260 DeviceCM* layer =
1261 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262 device->unref();
1263
1264 layer->fNext = fMCRec->fTopLayer;
1265 fMCRec->fLayer = layer;
1266 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001267}
1268
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001269int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001270 if (0xFF == alpha) {
1271 return this->saveLayer(bounds, nullptr);
1272 } else {
1273 SkPaint tmpPaint;
1274 tmpPaint.setAlpha(alpha);
1275 return this->saveLayer(bounds, &tmpPaint);
1276 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001277}
1278
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279void SkCanvas::internalRestore() {
1280 SkASSERT(fMCStack.count() != 0);
1281
1282 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001283 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001284
reed687fa1c2015-04-07 08:00:56 -07001285 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001286
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001287 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288 DeviceCM* layer = fMCRec->fLayer; // may be null
1289 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001290 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291
1292 // now do the normal restore()
1293 fMCRec->~MCRec(); // balanced in save()
1294 fMCStack.pop_back();
1295 fMCRec = (MCRec*)fMCStack.back();
1296
1297 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1298 since if we're being recorded, we don't want to record this (the
1299 recorder will have already recorded the restore).
1300 */
bsalomon49f085d2014-09-05 13:34:00 -07001301 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001303 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001304 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001305 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001306 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001308 delete layer;
reedb679ca82015-04-07 04:40:48 -07001309 } else {
1310 // we're at the root
reeda499f902015-05-01 09:34:31 -07001311 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001312 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315}
1316
reed4a8126e2014-09-22 07:29:03 -07001317SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001318 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001319 props = &fProps;
1320 }
1321 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001322}
1323
reed4a8126e2014-09-22 07:29:03 -07001324SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001325 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001326 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001327}
1328
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001329SkImageInfo SkCanvas::imageInfo() const {
1330 SkBaseDevice* dev = this->getDevice();
1331 if (dev) {
1332 return dev->imageInfo();
1333 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001334 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001335 }
1336}
1337
reed6ceeebd2016-03-09 14:26:26 -08001338#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001339const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001340 SkPixmap pmap;
reed6ceeebd2016-03-09 14:26:26 -08001341 if (this->peekPixels(&pmap)) {
1342 if (info) {
1343 *info = pmap.info();
1344 }
1345 if (rowBytes) {
1346 *rowBytes = pmap.rowBytes();
1347 }
1348 return pmap.addr();
reed884e97c2015-05-26 11:31:54 -07001349 }
reed6ceeebd2016-03-09 14:26:26 -08001350 return nullptr;
1351}
1352#endif
1353
1354bool SkCanvas::peekPixels(SkPixmap* pmap) {
1355 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001356}
1357
reed884e97c2015-05-26 11:31:54 -07001358bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001359 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001360 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001361}
1362
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001363void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001364 SkPixmap pmap;
1365 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001366 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001367 }
1368 if (info) {
1369 *info = pmap.info();
1370 }
1371 if (rowBytes) {
1372 *rowBytes = pmap.rowBytes();
1373 }
1374 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001375 *origin = this->getTopDevice(false)->getOrigin();
1376 }
reed884e97c2015-05-26 11:31:54 -07001377 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001378}
1379
reed884e97c2015-05-26 11:31:54 -07001380bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001381 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001382 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001383}
1384
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001387void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001388 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001390 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001391 paint = &tmp;
1392 }
reed@google.com4b226022011-01-11 18:32:13 +00001393
reed@google.com8926b162012-03-23 15:36:36 +00001394 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001395 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001396 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001397 paint = &looper.paint();
1398 SkImageFilter* filter = paint->getImageFilter();
1399 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001400 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001401 SkImageFilter::DeviceProxy proxy(dstDev);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001402 SkIPoint offset = SkIPoint::Make(0, 0);
robertphillips4418dba2016-03-07 12:45:14 -08001403 const SkBitmap& srcBM = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001404 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001405 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
robertphillips4418dba2016-03-07 12:45:14 -08001406 const SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
senorblancobe129b22014-08-08 07:14:35 -07001407 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reed4e23cda2016-01-11 10:56:59 -08001408 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
robertphillips4418dba2016-03-07 12:45:14 -08001409
1410 SkAutoTUnref<SkSpecialImage> srcImg(SkSpecialImage::internal_fromBM(&proxy, srcBM));
1411 if (!srcImg) {
1412 continue; // something disastrous happened
1413 }
1414
1415 SkAutoTUnref<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
1416 if (resultImg) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001417 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001418 tmpUnfiltered.setImageFilter(nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001419 SkBitmap resultBM;
1420 if (resultImg->internal_getBM(&resultBM)) {
1421 // TODO: add drawSprite(SkSpecialImage) to SkDevice? (see skbug.com/5073)
1422 dstDev->drawSprite(iter, resultBM, pos.x() + offset.x(), pos.y() + offset.y(),
1423 tmpUnfiltered);
1424 }
reed@google.com76dd2772012-01-05 21:15:07 +00001425 }
reed61f501f2015-04-29 08:34:00 -07001426 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001427 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001428 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001429 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001430 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001431 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001433 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434}
1435
reed32704672015-12-16 08:27:10 -08001436/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001437
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001438void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001439 SkMatrix m;
1440 m.setTranslate(dx, dy);
1441 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442}
1443
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001444void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001445 SkMatrix m;
1446 m.setScale(sx, sy);
1447 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448}
1449
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001450void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001451 SkMatrix m;
1452 m.setRotate(degrees);
1453 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454}
1455
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001456void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001457 SkMatrix m;
1458 m.setSkew(sx, sy);
1459 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001460}
1461
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001462void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001463 if (matrix.isIdentity()) {
1464 return;
1465 }
1466
reed2ff1fce2014-12-11 07:07:37 -08001467 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001469 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001470 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001471
1472 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001473}
1474
reed86a17e72015-05-14 12:25:22 -07001475void SkCanvas::setMatrix(const SkMatrix& matrix) {
1476 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001478 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001479 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001480 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001481}
1482
reed@android.com8a1c16f2008-12-17 15:59:43 +00001483void SkCanvas::resetMatrix() {
1484 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001485
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486 matrix.reset();
1487 this->setMatrix(matrix);
1488}
1489
1490//////////////////////////////////////////////////////////////////////////////
1491
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001492void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001493 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001494 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1495 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001496}
1497
1498void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001499#ifdef SK_ENABLE_CLIP_QUICKREJECT
1500 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001501 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001502 return false;
1503 }
1504
reed@google.com3b3e8952012-08-16 20:53:31 +00001505 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001506 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001507 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001508
reed687fa1c2015-04-07 08:00:56 -07001509 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001510 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001511 }
1512 }
1513#endif
1514
bsalomonac8cabd2015-11-20 18:53:07 -08001515 if (!fAllowSoftClip) {
1516 edgeStyle = kHard_ClipEdgeStyle;
1517 }
reed90ba0952015-11-20 13:42:47 -08001518
reedc64eff52015-11-21 12:39:45 -08001519 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1520 SkRect devR;
1521 if (rectStaysRect) {
1522 fMCRec->fMatrix.mapRect(&devR, rect);
1523 }
bsalomonac8cabd2015-11-20 18:53:07 -08001524
reedc64eff52015-11-21 12:39:45 -08001525 // Check if we can quick-accept the clip call (and do nothing)
1526 //
1527 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1528 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1529 // might allow lazy save/restores to eliminate entire save/restore blocks.
1530 //
1531 if (SkRegion::kIntersect_Op == op &&
1532 kHard_ClipEdgeStyle == edgeStyle
1533 && rectStaysRect)
1534 {
1535 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1536#if 0
1537 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1538 rect.left(), rect.top(), rect.right(), rect.bottom());
1539#endif
1540 return;
1541 }
1542 }
1543
1544 AutoValidateClip avc(this);
1545
1546 fDeviceCMDirty = true;
1547 fCachedLocalClipBoundsDirty = true;
1548
1549 if (rectStaysRect) {
1550 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1551 fClipStack->clipDevRect(devR, op, isAA);
senorblancoafc7cce2016-02-02 18:44:15 -08001552 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001553 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001554 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001555 // and clip against that, since it can handle any matrix. However, to
1556 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1557 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558 SkPath path;
1559
1560 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001561 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001562 }
1563}
1564
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001565void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001566 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001567 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001568 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001569 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1570 } else {
1571 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001572 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001573}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001574
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001575void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001576 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001577 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001578 AutoValidateClip avc(this);
1579
1580 fDeviceCMDirty = true;
1581 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001582 if (!fAllowSoftClip) {
1583 edgeStyle = kHard_ClipEdgeStyle;
1584 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001585
reed687fa1c2015-04-07 08:00:56 -07001586 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001587
senorblancoafc7cce2016-02-02 18:44:15 -08001588 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
robertphillips125f19a2015-11-23 09:00:05 -08001589 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001590 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001591 }
1592
1593 SkPath path;
1594 path.addRRect(rrect);
1595 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001596 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001597}
1598
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001599void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001600 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001601 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001602
1603 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1604 SkRect r;
1605 if (path.isRect(&r)) {
1606 this->onClipRect(r, op, edgeStyle);
1607 return;
1608 }
1609 SkRRect rrect;
1610 if (path.isOval(&r)) {
1611 rrect.setOval(r);
1612 this->onClipRRect(rrect, op, edgeStyle);
1613 return;
1614 }
1615 if (path.isRRect(&rrect)) {
1616 this->onClipRRect(rrect, op, edgeStyle);
1617 return;
1618 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001619 }
robertphillips39f05382015-11-24 09:30:12 -08001620
1621 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001622}
1623
1624void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001625#ifdef SK_ENABLE_CLIP_QUICKREJECT
1626 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001627 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001628 return false;
1629 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001630
reed@google.com3b3e8952012-08-16 20:53:31 +00001631 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001632 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001633 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001634
reed687fa1c2015-04-07 08:00:56 -07001635 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001636 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001637 }
1638 }
1639#endif
1640
reed@google.com5c3d1472011-02-22 19:12:23 +00001641 AutoValidateClip avc(this);
1642
reed@android.com8a1c16f2008-12-17 15:59:43 +00001643 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001644 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001645 if (!fAllowSoftClip) {
1646 edgeStyle = kHard_ClipEdgeStyle;
1647 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648
1649 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001650 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001651
reed@google.comfe701122011-11-08 19:41:23 +00001652 // Check if the transfomation, or the original path itself
1653 // made us empty. Note this can also happen if we contained NaN
1654 // values. computing the bounds detects this, and will set our
1655 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1656 if (devPath.getBounds().isEmpty()) {
1657 // resetting the path will remove any NaN or other wanky values
1658 // that might upset our scan converter.
1659 devPath.reset();
1660 }
1661
reed@google.com5c3d1472011-02-22 19:12:23 +00001662 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001663 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001664
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001665 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001666 bool clipIsAA = getClipStack()->asPath(&devPath);
1667 if (clipIsAA) {
1668 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001669 }
fmalita1a481fe2015-02-04 07:39:34 -08001670
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001671 op = SkRegion::kReplace_Op;
1672 }
1673
senorblancoafc7cce2016-02-02 18:44:15 -08001674 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001675}
1676
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001677void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001678 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001679 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001680}
1681
1682void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001683 AutoValidateClip avc(this);
1684
reed@android.com8a1c16f2008-12-17 15:59:43 +00001685 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001686 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687
reed@google.com5c3d1472011-02-22 19:12:23 +00001688 // todo: signal fClipStack that we have a region, and therefore (I guess)
1689 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001690 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001691
reed1f836ee2014-07-07 07:49:34 -07001692 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001693}
1694
reed@google.com819c9212011-02-23 18:56:55 +00001695#ifdef SK_DEBUG
1696void SkCanvas::validateClip() const {
1697 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001698 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001699 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001700 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001701 return;
1702 }
1703
reed@google.com819c9212011-02-23 18:56:55 +00001704 SkIRect ir;
1705 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001706 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001707
reed687fa1c2015-04-07 08:00:56 -07001708 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001709 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001710 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001711 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001712 case SkClipStack::Element::kRect_Type:
1713 element->getRect().round(&ir);
1714 tmpClip.op(ir, element->getOp());
1715 break;
1716 case SkClipStack::Element::kEmpty_Type:
1717 tmpClip.setEmpty();
1718 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001719 default: {
1720 SkPath path;
1721 element->asPath(&path);
senorblancoafc7cce2016-02-02 18:44:15 -08001722 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001723 break;
1724 }
reed@google.com819c9212011-02-23 18:56:55 +00001725 }
1726 }
reed@google.com819c9212011-02-23 18:56:55 +00001727}
1728#endif
1729
reed@google.com90c07ea2012-04-13 13:50:27 +00001730void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001731 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001732 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001733
halcanary96fcdcc2015-08-27 07:41:13 -07001734 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001735 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001736 }
1737}
1738
reed@google.com5c3d1472011-02-22 19:12:23 +00001739///////////////////////////////////////////////////////////////////////////////
1740
reed@google.com754de5f2014-02-24 19:38:20 +00001741bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001742 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001743}
1744
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001745bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001746 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001747}
1748
reed@google.com3b3e8952012-08-16 20:53:31 +00001749bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001750 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001751 return true;
1752
reed1f836ee2014-07-07 07:49:34 -07001753 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001754 return true;
1755 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001756
reed1f836ee2014-07-07 07:49:34 -07001757 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001758 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001759 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001760 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001761 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001762 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001763
reed@android.coma380ae42009-07-21 01:17:02 +00001764 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001765 // TODO: should we use | instead, or compare all 4 at once?
1766 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001767 return true;
1768 }
reed@google.comc0784db2013-12-13 21:16:12 +00001769 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001770 return true;
1771 }
1772 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001773 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001774}
1775
reed@google.com3b3e8952012-08-16 20:53:31 +00001776bool SkCanvas::quickReject(const SkPath& path) const {
1777 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001778}
1779
reed@google.com3b3e8952012-08-16 20:53:31 +00001780bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001781 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001782 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001783 return false;
1784 }
1785
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001786 SkMatrix inverse;
1787 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001788 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001789 if (bounds) {
1790 bounds->setEmpty();
1791 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001792 return false;
1793 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001794
bsalomon49f085d2014-09-05 13:34:00 -07001795 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001796 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001797 // adjust it outwards in case we are antialiasing
1798 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001799
reed@google.com8f4d2302013-12-17 16:44:46 +00001800 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1801 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001802 inverse.mapRect(bounds, r);
1803 }
1804 return true;
1805}
1806
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001807bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001808 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001809 if (clip.isEmpty()) {
1810 if (bounds) {
1811 bounds->setEmpty();
1812 }
1813 return false;
1814 }
1815
bsalomon49f085d2014-09-05 13:34:00 -07001816 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001817 *bounds = clip.getBounds();
1818 }
1819 return true;
1820}
1821
reed@android.com8a1c16f2008-12-17 15:59:43 +00001822const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001823 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001824}
1825
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001826const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001827 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001828}
1829
reed@google.com9c135db2014-03-12 18:28:35 +00001830GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1831 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001832 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001833}
1834
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001835GrContext* SkCanvas::getGrContext() {
1836#if SK_SUPPORT_GPU
1837 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001838 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001839 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001840 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001841 return renderTarget->getContext();
1842 }
1843 }
1844#endif
1845
halcanary96fcdcc2015-08-27 07:41:13 -07001846 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001847
1848}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001849
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001850void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1851 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001852 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001853 if (outer.isEmpty()) {
1854 return;
1855 }
1856 if (inner.isEmpty()) {
1857 this->drawRRect(outer, paint);
1858 return;
1859 }
1860
1861 // We don't have this method (yet), but technically this is what we should
1862 // be able to assert...
1863 // SkASSERT(outer.contains(inner));
1864 //
1865 // For now at least check for containment of bounds
1866 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1867
1868 this->onDrawDRRect(outer, inner, paint);
1869}
1870
reed41af9662015-01-05 07:49:08 -08001871// These need to stop being virtual -- clients need to override the onDraw... versions
1872
1873void SkCanvas::drawPaint(const SkPaint& paint) {
1874 this->onDrawPaint(paint);
1875}
1876
1877void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1878 this->onDrawRect(r, paint);
1879}
1880
1881void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1882 this->onDrawOval(r, paint);
1883}
1884
1885void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1886 this->onDrawRRect(rrect, paint);
1887}
1888
1889void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1890 this->onDrawPoints(mode, count, pts, paint);
1891}
1892
1893void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1894 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1895 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1896 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1897 indices, indexCount, paint);
1898}
1899
1900void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1901 this->onDrawPath(path, paint);
1902}
1903
reeda85d4d02015-05-06 12:56:48 -07001904void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001905 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001906 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001907}
1908
reede47829b2015-08-06 10:02:53 -07001909void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1910 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001911 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001912 if (dst.isEmpty() || src.isEmpty()) {
1913 return;
1914 }
1915 this->onDrawImageRect(image, &src, dst, paint, constraint);
1916}
reed41af9662015-01-05 07:49:08 -08001917
reed84984ef2015-07-17 07:09:43 -07001918void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1919 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001920 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001921 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001922}
1923
reede47829b2015-08-06 10:02:53 -07001924void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1925 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001926 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001927 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1928 constraint);
1929}
reede47829b2015-08-06 10:02:53 -07001930
reed4c21dc52015-06-25 12:32:03 -07001931void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1932 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001933 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001934 if (dst.isEmpty()) {
1935 return;
1936 }
1937 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001938 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001939 }
1940 this->onDrawImageNine(image, center, dst, paint);
1941}
1942
reed41af9662015-01-05 07:49:08 -08001943void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001944 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001945 return;
1946 }
reed41af9662015-01-05 07:49:08 -08001947 this->onDrawBitmap(bitmap, dx, dy, paint);
1948}
1949
reede47829b2015-08-06 10:02:53 -07001950void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001951 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001952 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001953 return;
1954 }
reede47829b2015-08-06 10:02:53 -07001955 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001956}
1957
reed84984ef2015-07-17 07:09:43 -07001958void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1959 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001960 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001961}
1962
reede47829b2015-08-06 10:02:53 -07001963void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1964 SrcRectConstraint constraint) {
1965 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1966 constraint);
1967}
reede47829b2015-08-06 10:02:53 -07001968
reed41af9662015-01-05 07:49:08 -08001969void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1970 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001971 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001972 return;
1973 }
reed4c21dc52015-06-25 12:32:03 -07001974 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001975 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001976 }
reed41af9662015-01-05 07:49:08 -08001977 this->onDrawBitmapNine(bitmap, center, dst, paint);
1978}
1979
reed71c3c762015-06-24 10:29:17 -07001980void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1981 const SkColor colors[], int count, SkXfermode::Mode mode,
1982 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001983 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001984 if (count <= 0) {
1985 return;
1986 }
1987 SkASSERT(atlas);
1988 SkASSERT(xform);
1989 SkASSERT(tex);
1990 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1991}
1992
reedf70b5312016-03-04 16:36:20 -08001993void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1994 if (key) {
1995 this->onDrawAnnotation(rect, key, value);
1996 }
1997}
1998
reede47829b2015-08-06 10:02:53 -07001999void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2000 const SkPaint* paint, SrcRectConstraint constraint) {
2001 if (src) {
2002 this->drawImageRect(image, *src, dst, paint, constraint);
2003 } else {
2004 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2005 dst, paint, constraint);
2006 }
2007}
2008void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2009 const SkPaint* paint, SrcRectConstraint constraint) {
2010 if (src) {
2011 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2012 } else {
2013 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2014 dst, paint, constraint);
2015 }
2016}
2017
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018//////////////////////////////////////////////////////////////////////////////
2019// These are the virtual drawing methods
2020//////////////////////////////////////////////////////////////////////////////
2021
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002022void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002023 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002024 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2025 }
2026}
2027
reed41af9662015-01-05 07:49:08 -08002028void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002029 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002030 this->internalDrawPaint(paint);
2031}
2032
2033void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002034 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002035
2036 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002037 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002038 }
2039
reed@google.com4e2b3d32011-04-07 14:18:59 +00002040 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002041}
2042
reed41af9662015-01-05 07:49:08 -08002043void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2044 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002045 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002046 if ((long)count <= 0) {
2047 return;
2048 }
2049
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002050 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002051 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002052 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002053 // special-case 2 points (common for drawing a single line)
2054 if (2 == count) {
2055 r.set(pts[0], pts[1]);
2056 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002057 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002058 }
senorblanco87e066e2015-10-28 11:23:36 -07002059 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2060 return;
2061 }
2062 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002063 }
reed@google.coma584aed2012-05-16 14:06:02 +00002064
halcanary96fcdcc2015-08-27 07:41:13 -07002065 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002066
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002067 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002068
reed@android.com8a1c16f2008-12-17 15:59:43 +00002069 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002070 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002071 }
reed@google.com4b226022011-01-11 18:32:13 +00002072
reed@google.com4e2b3d32011-04-07 14:18:59 +00002073 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002074}
2075
reed41af9662015-01-05 07:49:08 -08002076void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002077 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002078 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002079 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002080 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002081 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2082 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2083 SkRect tmp(r);
2084 tmp.sort();
2085
senorblanco87e066e2015-10-28 11:23:36 -07002086 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2087 return;
2088 }
2089 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002090 }
reed@google.com4b226022011-01-11 18:32:13 +00002091
reedc83a2972015-07-16 07:40:45 -07002092 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093
2094 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002095 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002096 }
2097
reed@google.com4e2b3d32011-04-07 14:18:59 +00002098 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099}
2100
reed41af9662015-01-05 07:49:08 -08002101void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002102 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002103 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002104 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002105 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002106 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2107 return;
2108 }
2109 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002110 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002111
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002112 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002113
2114 while (iter.next()) {
2115 iter.fDevice->drawOval(iter, oval, looper.paint());
2116 }
2117
2118 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002119}
2120
reed41af9662015-01-05 07:49:08 -08002121void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002122 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002123 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002124 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002125 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002126 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2127 return;
2128 }
2129 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002130 }
2131
2132 if (rrect.isRect()) {
2133 // call the non-virtual version
2134 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002135 return;
2136 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002137 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002138 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2139 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002140 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002141
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002142 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002143
2144 while (iter.next()) {
2145 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2146 }
2147
2148 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002149}
2150
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002151void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2152 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002153 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002154 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002155 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002156 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2157 return;
2158 }
2159 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002160 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002161
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002162 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002163
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002164 while (iter.next()) {
2165 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2166 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002167
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002168 LOOPER_END
2169}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002170
reed41af9662015-01-05 07:49:08 -08002171void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002172 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002173 if (!path.isFinite()) {
2174 return;
2175 }
2176
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002177 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002178 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002179 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002180 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002181 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2182 return;
2183 }
2184 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002185 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002186
2187 const SkRect& r = path.getBounds();
2188 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002189 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002190 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002191 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002192 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002193 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002194
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002195 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002196
2197 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002198 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002199 }
2200
reed@google.com4e2b3d32011-04-07 14:18:59 +00002201 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002202}
2203
reed262a71b2015-12-05 13:07:27 -08002204bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002205 if (!paint.getImageFilter()) {
2206 return false;
2207 }
2208
2209 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002210 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002211 return false;
2212 }
2213
2214 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2215 // Once we can filter and the filter will return a result larger than itself, we should be
2216 // able to remove this constraint.
2217 // skbug.com/4526
2218 //
2219 SkPoint pt;
2220 ctm.mapXY(x, y, &pt);
2221 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2222 return ir.contains(fMCRec->fRasterClip.getBounds());
2223}
2224
reeda85d4d02015-05-06 12:56:48 -07002225void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002226 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002227 SkRect bounds = SkRect::MakeXYWH(x, y,
2228 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002229 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002230 SkRect tmp = bounds;
2231 if (paint) {
2232 paint->computeFastBounds(tmp, &tmp);
2233 }
2234 if (this->quickReject(tmp)) {
2235 return;
2236 }
reeda85d4d02015-05-06 12:56:48 -07002237 }
2238
2239 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002240 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002241 paint = lazy.init();
2242 }
reed262a71b2015-12-05 13:07:27 -08002243
reed129ed1c2016-02-22 06:42:31 -08002244 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2245 *paint);
2246 if (drawAsSprite && paint->getImageFilter()) {
2247 SkBitmap bitmap;
2248 if (!as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2249 drawAsSprite = false;
2250 } else{
2251 // Until imagefilters are updated, they cannot handle any src type but N32...
2252 if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) {
2253 drawAsSprite = false;
2254 }
2255 }
2256 }
2257
reed262a71b2015-12-05 13:07:27 -08002258 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2259
reeda85d4d02015-05-06 12:56:48 -07002260 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002261 const SkPaint& pnt = looper.paint();
2262 if (drawAsSprite && pnt.getImageFilter()) {
2263 SkBitmap bitmap;
2264 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2265 SkPoint pt;
2266 iter.fMatrix->mapXY(x, y, &pt);
2267 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2268 SkScalarRoundToInt(pt.fX),
2269 SkScalarRoundToInt(pt.fY), pnt);
2270 }
2271 } else {
2272 iter.fDevice->drawImage(iter, image, x, y, pnt);
2273 }
reeda85d4d02015-05-06 12:56:48 -07002274 }
2275
2276 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002277}
2278
reed41af9662015-01-05 07:49:08 -08002279void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002280 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002281 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002282 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002283 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002284 if (paint) {
2285 paint->computeFastBounds(dst, &storage);
2286 }
2287 if (this->quickReject(storage)) {
2288 return;
2289 }
reeda85d4d02015-05-06 12:56:48 -07002290 }
2291 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002292 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002293 paint = lazy.init();
2294 }
2295
senorblancoc41e7e12015-12-07 12:51:30 -08002296 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002297 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002298
2299 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002300 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002301 }
2302
2303 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002304}
2305
reed41af9662015-01-05 07:49:08 -08002306void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002307 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308 SkDEBUGCODE(bitmap.validate();)
2309
reed33366972015-10-08 09:22:02 -07002310 if (bitmap.drawsNothing()) {
2311 return;
2312 }
2313
2314 SkLazyPaint lazy;
2315 if (nullptr == paint) {
2316 paint = lazy.init();
2317 }
2318
2319 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2320
2321 SkRect storage;
2322 const SkRect* bounds = nullptr;
2323 if (paint->canComputeFastBounds()) {
2324 bitmap.getBounds(&storage);
2325 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002326 SkRect tmp = storage;
2327 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2328 return;
2329 }
2330 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002331 }
reed@google.com4b226022011-01-11 18:32:13 +00002332
reed129ed1c2016-02-22 06:42:31 -08002333 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2334 *paint);
2335 if (drawAsSprite && paint->getImageFilter()) {
2336 // Until imagefilters are updated, they cannot handle any src type but N32...
2337 if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) {
2338 drawAsSprite = false;
2339 }
2340 }
2341
reed262a71b2015-12-05 13:07:27 -08002342 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002343
2344 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002345 const SkPaint& pnt = looper.paint();
2346 if (drawAsSprite && pnt.getImageFilter()) {
2347 SkPoint pt;
2348 iter.fMatrix->mapXY(x, y, &pt);
2349 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2350 SkScalarRoundToInt(pt.fX),
2351 SkScalarRoundToInt(pt.fY), pnt);
2352 } else {
2353 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2354 }
reed33366972015-10-08 09:22:02 -07002355 }
reed262a71b2015-12-05 13:07:27 -08002356
reed33366972015-10-08 09:22:02 -07002357 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002358}
2359
reed@google.com9987ec32011-09-07 11:57:52 +00002360// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002361void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002362 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002363 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002364 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002365 return;
2366 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002367
halcanary96fcdcc2015-08-27 07:41:13 -07002368 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002369 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002370 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2371 return;
2372 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002373 }
reed@google.com3d608122011-11-21 15:16:16 +00002374
reed@google.com33535f32012-09-25 15:37:50 +00002375 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002376 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002377 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002378 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002379
senorblancoc41e7e12015-12-07 12:51:30 -08002380 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002381 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002382
reed@google.com33535f32012-09-25 15:37:50 +00002383 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002384 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002385 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002386
reed@google.com33535f32012-09-25 15:37:50 +00002387 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002388}
2389
reed41af9662015-01-05 07:49:08 -08002390void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002391 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002392 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002393 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002394 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002395}
2396
reed4c21dc52015-06-25 12:32:03 -07002397void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2398 const SkPaint* paint) {
2399 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2400
halcanary96fcdcc2015-08-27 07:41:13 -07002401 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002402 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002403 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2404 return;
2405 }
reed@google.com3d608122011-11-21 15:16:16 +00002406 }
reed4c21dc52015-06-25 12:32:03 -07002407
2408 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002409 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002410 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002411 }
reed4c21dc52015-06-25 12:32:03 -07002412
senorblancoc41e7e12015-12-07 12:51:30 -08002413 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002414
2415 while (iter.next()) {
2416 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002417 }
reed4c21dc52015-06-25 12:32:03 -07002418
2419 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002420}
2421
reed41af9662015-01-05 07:49:08 -08002422void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2423 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002424 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002425 SkDEBUGCODE(bitmap.validate();)
2426
halcanary96fcdcc2015-08-27 07:41:13 -07002427 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002428 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002429 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2430 return;
2431 }
reed4c21dc52015-06-25 12:32:03 -07002432 }
2433
2434 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002435 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002436 paint = lazy.init();
2437 }
2438
senorblancoc41e7e12015-12-07 12:51:30 -08002439 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002440
2441 while (iter.next()) {
2442 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2443 }
2444
2445 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002446}
2447
reed@google.comf67e4cf2011-03-15 20:56:58 +00002448class SkDeviceFilteredPaint {
2449public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002450 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002451 uint32_t filteredFlags = device->filterTextFlags(paint);
2452 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002453 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002454 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002455 fPaint = newPaint;
2456 } else {
2457 fPaint = &paint;
2458 }
2459 }
2460
reed@google.comf67e4cf2011-03-15 20:56:58 +00002461 const SkPaint& paint() const { return *fPaint; }
2462
2463private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002464 const SkPaint* fPaint;
2465 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002466};
2467
bungeman@google.com52c748b2011-08-22 21:30:43 +00002468void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2469 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002470 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002471 draw.fDevice->drawRect(draw, r, paint);
2472 } else {
2473 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002474 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002475 draw.fDevice->drawRect(draw, r, p);
2476 }
2477}
2478
2479void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2480 const char text[], size_t byteLength,
2481 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002482 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002483
2484 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002485 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002486 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002487 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002488 return;
2489 }
2490
2491 SkScalar width = 0;
2492 SkPoint start;
2493
2494 start.set(0, 0); // to avoid warning
2495 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2496 SkPaint::kStrikeThruText_Flag)) {
2497 width = paint.measureText(text, byteLength);
2498
2499 SkScalar offsetX = 0;
2500 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2501 offsetX = SkScalarHalf(width);
2502 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2503 offsetX = width;
2504 }
2505 start.set(x - offsetX, y);
2506 }
2507
2508 if (0 == width) {
2509 return;
2510 }
2511
2512 uint32_t flags = paint.getFlags();
2513
2514 if (flags & (SkPaint::kUnderlineText_Flag |
2515 SkPaint::kStrikeThruText_Flag)) {
2516 SkScalar textSize = paint.getTextSize();
2517 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2518 SkRect r;
2519
2520 r.fLeft = start.fX;
2521 r.fRight = start.fX + width;
2522
2523 if (flags & SkPaint::kUnderlineText_Flag) {
2524 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2525 start.fY);
2526 r.fTop = offset;
2527 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002528 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002529 }
2530 if (flags & SkPaint::kStrikeThruText_Flag) {
2531 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2532 start.fY);
2533 r.fTop = offset;
2534 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002535 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002536 }
2537 }
2538}
2539
reed@google.come0d9ce82014-04-23 04:00:17 +00002540void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2541 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002542 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543
2544 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002545 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002546 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002547 DrawTextDecorations(iter, dfp.paint(),
2548 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002549 }
2550
reed@google.com4e2b3d32011-04-07 14:18:59 +00002551 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002552}
2553
reed@google.come0d9ce82014-04-23 04:00:17 +00002554void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2555 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002556 SkPoint textOffset = SkPoint::Make(0, 0);
2557
halcanary96fcdcc2015-08-27 07:41:13 -07002558 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002559
reed@android.com8a1c16f2008-12-17 15:59:43 +00002560 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002561 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002562 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002563 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002564 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002565
reed@google.com4e2b3d32011-04-07 14:18:59 +00002566 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002567}
2568
reed@google.come0d9ce82014-04-23 04:00:17 +00002569void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2570 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002571
2572 SkPoint textOffset = SkPoint::Make(0, constY);
2573
halcanary96fcdcc2015-08-27 07:41:13 -07002574 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002575
reed@android.com8a1c16f2008-12-17 15:59:43 +00002576 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002577 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002578 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002579 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002580 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002581
reed@google.com4e2b3d32011-04-07 14:18:59 +00002582 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002583}
2584
reed@google.come0d9ce82014-04-23 04:00:17 +00002585void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2586 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002587 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002588
reed@android.com8a1c16f2008-12-17 15:59:43 +00002589 while (iter.next()) {
2590 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002591 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002592 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002593
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002594 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002595}
2596
fmalita00d5c2c2014-08-21 08:53:26 -07002597void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2598 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002599
fmalita85d5eb92015-03-04 11:20:12 -08002600 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002601 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002602 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002603 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002604 SkRect tmp;
2605 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2606 return;
2607 }
2608 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002609 }
2610
fmalita024f9962015-03-03 19:08:17 -08002611 // We cannot filter in the looper as we normally do, because the paint is
2612 // incomplete at this point (text-related attributes are embedded within blob run paints).
2613 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002614 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002615
fmalita85d5eb92015-03-04 11:20:12 -08002616 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002617
fmalitaaa1b9122014-08-28 14:32:24 -07002618 while (iter.next()) {
2619 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002620 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002621 }
2622
fmalitaaa1b9122014-08-28 14:32:24 -07002623 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002624
2625 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002626}
2627
reed@google.come0d9ce82014-04-23 04:00:17 +00002628// These will become non-virtual, so they always call the (virtual) onDraw... method
2629void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2630 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002631 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002632 this->onDrawText(text, byteLength, x, y, paint);
2633}
2634void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2635 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002636 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002637 this->onDrawPosText(text, byteLength, pos, paint);
2638}
2639void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2640 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002641 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002642 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2643}
2644void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2645 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002646 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002647 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2648}
fmalita00d5c2c2014-08-21 08:53:26 -07002649void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2650 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002651 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002652 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002653 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002654}
reed@google.come0d9ce82014-04-23 04:00:17 +00002655
reed41af9662015-01-05 07:49:08 -08002656void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2657 const SkPoint verts[], const SkPoint texs[],
2658 const SkColor colors[], SkXfermode* xmode,
2659 const uint16_t indices[], int indexCount,
2660 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002661 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002662 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002663
reed@android.com8a1c16f2008-12-17 15:59:43 +00002664 while (iter.next()) {
2665 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002666 colors, xmode, indices, indexCount,
2667 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002668 }
reed@google.com4b226022011-01-11 18:32:13 +00002669
reed@google.com4e2b3d32011-04-07 14:18:59 +00002670 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002671}
2672
dandovb3c9d1c2014-08-12 08:34:29 -07002673void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2674 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002675 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002676 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002677 return;
2678 }
mtklein6cfa73a2014-08-13 13:33:49 -07002679
dandovecfff212014-08-04 10:02:00 -07002680 // Since a patch is always within the convex hull of the control points, we discard it when its
2681 // bounding rectangle is completely outside the current clip.
2682 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002683 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002684 if (this->quickReject(bounds)) {
2685 return;
2686 }
mtklein6cfa73a2014-08-13 13:33:49 -07002687
dandovb3c9d1c2014-08-12 08:34:29 -07002688 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2689}
2690
2691void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2692 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2693
halcanary96fcdcc2015-08-27 07:41:13 -07002694 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002695
dandovecfff212014-08-04 10:02:00 -07002696 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002697 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002698 }
mtklein6cfa73a2014-08-13 13:33:49 -07002699
dandovecfff212014-08-04 10:02:00 -07002700 LOOPER_END
2701}
2702
reeda8db7282015-07-07 10:22:31 -07002703void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002704 RETURN_ON_NULL(dr);
2705 if (x || y) {
2706 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2707 this->onDrawDrawable(dr, &matrix);
2708 } else {
2709 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002710 }
2711}
2712
reeda8db7282015-07-07 10:22:31 -07002713void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002714 RETURN_ON_NULL(dr);
2715 if (matrix && matrix->isIdentity()) {
2716 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002717 }
reede3b38ce2016-01-08 09:18:44 -08002718 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002719}
2720
2721void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2722 SkRect bounds = dr->getBounds();
2723 if (matrix) {
2724 matrix->mapRect(&bounds);
2725 }
2726 if (this->quickReject(bounds)) {
2727 return;
2728 }
2729 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002730}
2731
reed71c3c762015-06-24 10:29:17 -07002732void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2733 const SkColor colors[], int count, SkXfermode::Mode mode,
2734 const SkRect* cull, const SkPaint* paint) {
2735 if (cull && this->quickReject(*cull)) {
2736 return;
2737 }
2738
2739 SkPaint pnt;
2740 if (paint) {
2741 pnt = *paint;
2742 }
2743
halcanary96fcdcc2015-08-27 07:41:13 -07002744 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002745 while (iter.next()) {
2746 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2747 }
2748 LOOPER_END
2749}
2750
reedf70b5312016-03-04 16:36:20 -08002751void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2752 SkASSERT(key);
2753
2754 SkPaint paint;
2755 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2756 while (iter.next()) {
2757 iter.fDevice->drawAnnotation(iter, rect, key, value);
2758 }
2759 LOOPER_END
2760}
2761
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762//////////////////////////////////////////////////////////////////////////////
2763// These methods are NOT virtual, and therefore must call back into virtual
2764// methods, rather than actually drawing themselves.
2765//////////////////////////////////////////////////////////////////////////////
2766
2767void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002768 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002769 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 SkPaint paint;
2771
2772 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002773 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002774 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775 }
2776 this->drawPaint(paint);
2777}
2778
reed@android.com845fdac2009-06-23 03:01:32 +00002779void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002780 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 SkPaint paint;
2782
2783 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002784 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002785 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 }
2787 this->drawPaint(paint);
2788}
2789
2790void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002791 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002792 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002793
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794 pt.set(x, y);
2795 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2796}
2797
2798void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002799 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002800 SkPoint pt;
2801 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002802
reed@android.com8a1c16f2008-12-17 15:59:43 +00002803 pt.set(x, y);
2804 paint.setColor(color);
2805 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2806}
2807
2808void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2809 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002810 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002811 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002812
reed@android.com8a1c16f2008-12-17 15:59:43 +00002813 pts[0].set(x0, y0);
2814 pts[1].set(x1, y1);
2815 this->drawPoints(kLines_PointMode, 2, pts, paint);
2816}
2817
2818void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2819 SkScalar right, SkScalar bottom,
2820 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002821 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002822 SkRect r;
2823
2824 r.set(left, top, right, bottom);
2825 this->drawRect(r, paint);
2826}
2827
2828void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2829 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002830 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831 if (radius < 0) {
2832 radius = 0;
2833 }
2834
2835 SkRect r;
2836 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002837 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002838}
2839
2840void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2841 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002842 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002843 if (rx > 0 && ry > 0) {
2844 if (paint.canComputeFastBounds()) {
2845 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002846 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847 return;
2848 }
2849 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002850 SkRRect rrect;
2851 rrect.setRectXY(r, rx, ry);
2852 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002853 } else {
2854 this->drawRect(r, paint);
2855 }
2856}
2857
reed@android.com8a1c16f2008-12-17 15:59:43 +00002858void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2859 SkScalar sweepAngle, bool useCenter,
2860 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002861 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002862 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2863 this->drawOval(oval, paint);
2864 } else {
2865 SkPath path;
2866 if (useCenter) {
2867 path.moveTo(oval.centerX(), oval.centerY());
2868 }
2869 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2870 if (useCenter) {
2871 path.close();
2872 }
2873 this->drawPath(path, paint);
2874 }
2875}
2876
2877void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2878 const SkPath& path, SkScalar hOffset,
2879 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002880 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002881 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002882
reed@android.com8a1c16f2008-12-17 15:59:43 +00002883 matrix.setTranslate(hOffset, vOffset);
2884 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2885}
2886
reed@android.comf76bacf2009-05-13 14:00:33 +00002887///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002888
2889/**
2890 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2891 * against the playback cost of recursing into the subpicture to get at its actual ops.
2892 *
2893 * For now we pick a conservatively small value, though measurement (and other heuristics like
2894 * the type of ops contained) may justify changing this value.
2895 */
2896#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002897
reedd5fa1a42014-08-09 11:08:05 -07002898void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002899 RETURN_ON_NULL(picture);
2900
reed1c2c4412015-04-30 13:09:24 -07002901 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002902 if (matrix && matrix->isIdentity()) {
2903 matrix = nullptr;
2904 }
2905 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2906 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2907 picture->playback(this);
2908 } else {
2909 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002910 }
2911}
robertphillips9b14f262014-06-04 05:40:44 -07002912
reedd5fa1a42014-08-09 11:08:05 -07002913void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2914 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002915 if (!paint || paint->canComputeFastBounds()) {
2916 SkRect bounds = picture->cullRect();
2917 if (paint) {
2918 paint->computeFastBounds(bounds, &bounds);
2919 }
2920 if (matrix) {
2921 matrix->mapRect(&bounds);
2922 }
2923 if (this->quickReject(bounds)) {
2924 return;
2925 }
2926 }
2927
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002928 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002929 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002930 // Canvas has to first give the device the opportunity to render
2931 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002932 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002933 return; // the device has rendered the entire picture
2934 }
2935 }
2936
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002937 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002938 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002939}
2940
reed@android.com8a1c16f2008-12-17 15:59:43 +00002941///////////////////////////////////////////////////////////////////////////////
2942///////////////////////////////////////////////////////////////////////////////
2943
2944SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002945 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002946
2947 SkASSERT(canvas);
2948
2949 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2950 fDone = !fImpl->next();
2951}
2952
2953SkCanvas::LayerIter::~LayerIter() {
2954 fImpl->~SkDrawIter();
2955}
2956
2957void SkCanvas::LayerIter::next() {
2958 fDone = !fImpl->next();
2959}
2960
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002961SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002962 return fImpl->getDevice();
2963}
2964
2965const SkMatrix& SkCanvas::LayerIter::matrix() const {
2966 return fImpl->getMatrix();
2967}
2968
2969const SkPaint& SkCanvas::LayerIter::paint() const {
2970 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002971 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002972 paint = &fDefaultPaint;
2973 }
2974 return *paint;
2975}
2976
2977const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2978int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2979int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002980
2981///////////////////////////////////////////////////////////////////////////////
2982
fmalitac3b589a2014-06-05 12:40:07 -07002983SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002984
2985///////////////////////////////////////////////////////////////////////////////
2986
2987static bool supported_for_raster_canvas(const SkImageInfo& info) {
2988 switch (info.alphaType()) {
2989 case kPremul_SkAlphaType:
2990 case kOpaque_SkAlphaType:
2991 break;
2992 default:
2993 return false;
2994 }
2995
2996 switch (info.colorType()) {
2997 case kAlpha_8_SkColorType:
2998 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002999 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003000 break;
3001 default:
3002 return false;
3003 }
3004
3005 return true;
3006}
3007
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003008SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3009 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003010 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003011 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003012
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003013 SkBitmap bitmap;
3014 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003015 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003016 }
halcanary385fe4d2015-08-26 13:07:48 -07003017 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003018}
reedd5fa1a42014-08-09 11:08:05 -07003019
3020///////////////////////////////////////////////////////////////////////////////
3021
3022SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003023 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003024 : fCanvas(canvas)
3025 , fSaveCount(canvas->getSaveCount())
3026{
bsalomon49f085d2014-09-05 13:34:00 -07003027 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003028 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003029 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003030 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003031 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003032 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003033 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003034 canvas->save();
3035 }
mtklein6cfa73a2014-08-13 13:33:49 -07003036
bsalomon49f085d2014-09-05 13:34:00 -07003037 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003038 canvas->concat(*matrix);
3039 }
3040}
3041
3042SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3043 fCanvas->restoreToCount(fSaveCount);
3044}