blob: 35710fb3171514d4dd560009a941f3b54ef411b5 [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
1338const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001339 SkPixmap pmap;
1340 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001341 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001342 }
1343 if (info) {
1344 *info = pmap.info();
1345 }
1346 if (rowBytes) {
1347 *rowBytes = pmap.rowBytes();
1348 }
1349 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001350}
1351
reed884e97c2015-05-26 11:31:54 -07001352bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001353 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001354 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001355}
1356
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001357void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001358 SkPixmap pmap;
1359 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001360 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001361 }
1362 if (info) {
1363 *info = pmap.info();
1364 }
1365 if (rowBytes) {
1366 *rowBytes = pmap.rowBytes();
1367 }
1368 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001369 *origin = this->getTopDevice(false)->getOrigin();
1370 }
reed884e97c2015-05-26 11:31:54 -07001371 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001372}
1373
reed884e97c2015-05-26 11:31:54 -07001374bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001375 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001376 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001377}
1378
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001380
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001381void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001382 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001384 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385 paint = &tmp;
1386 }
reed@google.com4b226022011-01-11 18:32:13 +00001387
reed@google.com8926b162012-03-23 15:36:36 +00001388 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001390 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001391 paint = &looper.paint();
1392 SkImageFilter* filter = paint->getImageFilter();
1393 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001394 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001395 SkImageFilter::DeviceProxy proxy(dstDev);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001396 SkIPoint offset = SkIPoint::Make(0, 0);
robertphillips4418dba2016-03-07 12:45:14 -08001397 const SkBitmap& srcBM = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001398 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001399 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
robertphillips4418dba2016-03-07 12:45:14 -08001400 const SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
senorblancobe129b22014-08-08 07:14:35 -07001401 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reed4e23cda2016-01-11 10:56:59 -08001402 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
robertphillips4418dba2016-03-07 12:45:14 -08001403
1404 SkAutoTUnref<SkSpecialImage> srcImg(SkSpecialImage::internal_fromBM(&proxy, srcBM));
1405 if (!srcImg) {
1406 continue; // something disastrous happened
1407 }
1408
1409 SkAutoTUnref<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
1410 if (resultImg) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001411 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001412 tmpUnfiltered.setImageFilter(nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001413 SkBitmap resultBM;
1414 if (resultImg->internal_getBM(&resultBM)) {
1415 // TODO: add drawSprite(SkSpecialImage) to SkDevice? (see skbug.com/5073)
1416 dstDev->drawSprite(iter, resultBM, pos.x() + offset.x(), pos.y() + offset.y(),
1417 tmpUnfiltered);
1418 }
reed@google.com76dd2772012-01-05 21:15:07 +00001419 }
reed61f501f2015-04-29 08:34:00 -07001420 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001421 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001422 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001423 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001424 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001425 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001427 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428}
1429
reed32704672015-12-16 08:27:10 -08001430/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001431
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001432void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001433 SkMatrix m;
1434 m.setTranslate(dx, dy);
1435 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436}
1437
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001438void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001439 SkMatrix m;
1440 m.setScale(sx, sy);
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::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001445 SkMatrix m;
1446 m.setRotate(degrees);
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::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001451 SkMatrix m;
1452 m.setSkew(sx, sy);
1453 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001454}
1455
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001456void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001457 if (matrix.isIdentity()) {
1458 return;
1459 }
1460
reed2ff1fce2014-12-11 07:07:37 -08001461 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001463 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001464 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001465
1466 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001467}
1468
reed86a17e72015-05-14 12:25:22 -07001469void SkCanvas::setMatrix(const SkMatrix& matrix) {
1470 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001471 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001472 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001473 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001474 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001475}
1476
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477void SkCanvas::resetMatrix() {
1478 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001479
reed@android.com8a1c16f2008-12-17 15:59:43 +00001480 matrix.reset();
1481 this->setMatrix(matrix);
1482}
1483
1484//////////////////////////////////////////////////////////////////////////////
1485
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001486void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001487 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001488 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1489 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001490}
1491
1492void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001493#ifdef SK_ENABLE_CLIP_QUICKREJECT
1494 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001495 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001496 return false;
1497 }
1498
reed@google.com3b3e8952012-08-16 20:53:31 +00001499 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001500 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001501 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001502
reed687fa1c2015-04-07 08:00:56 -07001503 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001504 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001505 }
1506 }
1507#endif
1508
bsalomonac8cabd2015-11-20 18:53:07 -08001509 if (!fAllowSoftClip) {
1510 edgeStyle = kHard_ClipEdgeStyle;
1511 }
reed90ba0952015-11-20 13:42:47 -08001512
reedc64eff52015-11-21 12:39:45 -08001513 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1514 SkRect devR;
1515 if (rectStaysRect) {
1516 fMCRec->fMatrix.mapRect(&devR, rect);
1517 }
bsalomonac8cabd2015-11-20 18:53:07 -08001518
reedc64eff52015-11-21 12:39:45 -08001519 // Check if we can quick-accept the clip call (and do nothing)
1520 //
1521 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1522 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1523 // might allow lazy save/restores to eliminate entire save/restore blocks.
1524 //
1525 if (SkRegion::kIntersect_Op == op &&
1526 kHard_ClipEdgeStyle == edgeStyle
1527 && rectStaysRect)
1528 {
1529 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1530#if 0
1531 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1532 rect.left(), rect.top(), rect.right(), rect.bottom());
1533#endif
1534 return;
1535 }
1536 }
1537
1538 AutoValidateClip avc(this);
1539
1540 fDeviceCMDirty = true;
1541 fCachedLocalClipBoundsDirty = true;
1542
1543 if (rectStaysRect) {
1544 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1545 fClipStack->clipDevRect(devR, op, isAA);
senorblancoafc7cce2016-02-02 18:44:15 -08001546 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001547 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001548 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001549 // and clip against that, since it can handle any matrix. However, to
1550 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1551 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001552 SkPath path;
1553
1554 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001555 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001556 }
1557}
1558
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001559void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001560 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001561 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001562 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001563 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1564 } else {
1565 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001566 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001567}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001568
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001569void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001570 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001571 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001572 AutoValidateClip avc(this);
1573
1574 fDeviceCMDirty = true;
1575 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001576 if (!fAllowSoftClip) {
1577 edgeStyle = kHard_ClipEdgeStyle;
1578 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001579
reed687fa1c2015-04-07 08:00:56 -07001580 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001581
senorblancoafc7cce2016-02-02 18:44:15 -08001582 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
robertphillips125f19a2015-11-23 09:00:05 -08001583 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001584 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001585 }
1586
1587 SkPath path;
1588 path.addRRect(rrect);
1589 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001590 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001591}
1592
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001593void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001594 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001595 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001596
1597 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1598 SkRect r;
1599 if (path.isRect(&r)) {
1600 this->onClipRect(r, op, edgeStyle);
1601 return;
1602 }
1603 SkRRect rrect;
1604 if (path.isOval(&r)) {
1605 rrect.setOval(r);
1606 this->onClipRRect(rrect, op, edgeStyle);
1607 return;
1608 }
1609 if (path.isRRect(&rrect)) {
1610 this->onClipRRect(rrect, op, edgeStyle);
1611 return;
1612 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001613 }
robertphillips39f05382015-11-24 09:30:12 -08001614
1615 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001616}
1617
1618void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001619#ifdef SK_ENABLE_CLIP_QUICKREJECT
1620 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001621 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001622 return false;
1623 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001624
reed@google.com3b3e8952012-08-16 20:53:31 +00001625 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001626 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001627 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001628
reed687fa1c2015-04-07 08:00:56 -07001629 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001630 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001631 }
1632 }
1633#endif
1634
reed@google.com5c3d1472011-02-22 19:12:23 +00001635 AutoValidateClip avc(this);
1636
reed@android.com8a1c16f2008-12-17 15:59:43 +00001637 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001638 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001639 if (!fAllowSoftClip) {
1640 edgeStyle = kHard_ClipEdgeStyle;
1641 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001642
1643 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001644 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001645
reed@google.comfe701122011-11-08 19:41:23 +00001646 // Check if the transfomation, or the original path itself
1647 // made us empty. Note this can also happen if we contained NaN
1648 // values. computing the bounds detects this, and will set our
1649 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1650 if (devPath.getBounds().isEmpty()) {
1651 // resetting the path will remove any NaN or other wanky values
1652 // that might upset our scan converter.
1653 devPath.reset();
1654 }
1655
reed@google.com5c3d1472011-02-22 19:12:23 +00001656 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001657 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001658
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001659 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001660 bool clipIsAA = getClipStack()->asPath(&devPath);
1661 if (clipIsAA) {
1662 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001663 }
fmalita1a481fe2015-02-04 07:39:34 -08001664
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001665 op = SkRegion::kReplace_Op;
1666 }
1667
senorblancoafc7cce2016-02-02 18:44:15 -08001668 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001669}
1670
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001671void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001672 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001673 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001674}
1675
1676void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001677 AutoValidateClip avc(this);
1678
reed@android.com8a1c16f2008-12-17 15:59:43 +00001679 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001680 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681
reed@google.com5c3d1472011-02-22 19:12:23 +00001682 // todo: signal fClipStack that we have a region, and therefore (I guess)
1683 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001684 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001685
reed1f836ee2014-07-07 07:49:34 -07001686 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687}
1688
reed@google.com819c9212011-02-23 18:56:55 +00001689#ifdef SK_DEBUG
1690void SkCanvas::validateClip() const {
1691 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001692 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001693 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001694 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001695 return;
1696 }
1697
reed@google.com819c9212011-02-23 18:56:55 +00001698 SkIRect ir;
1699 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001700 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001701
reed687fa1c2015-04-07 08:00:56 -07001702 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001703 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001704 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001705 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001706 case SkClipStack::Element::kRect_Type:
1707 element->getRect().round(&ir);
1708 tmpClip.op(ir, element->getOp());
1709 break;
1710 case SkClipStack::Element::kEmpty_Type:
1711 tmpClip.setEmpty();
1712 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001713 default: {
1714 SkPath path;
1715 element->asPath(&path);
senorblancoafc7cce2016-02-02 18:44:15 -08001716 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001717 break;
1718 }
reed@google.com819c9212011-02-23 18:56:55 +00001719 }
1720 }
reed@google.com819c9212011-02-23 18:56:55 +00001721}
1722#endif
1723
reed@google.com90c07ea2012-04-13 13:50:27 +00001724void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001725 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001726 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001727
halcanary96fcdcc2015-08-27 07:41:13 -07001728 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001729 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001730 }
1731}
1732
reed@google.com5c3d1472011-02-22 19:12:23 +00001733///////////////////////////////////////////////////////////////////////////////
1734
reed@google.com754de5f2014-02-24 19:38:20 +00001735bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001736 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001737}
1738
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001739bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001740 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001741}
1742
reed@google.com3b3e8952012-08-16 20:53:31 +00001743bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001744 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001745 return true;
1746
reed1f836ee2014-07-07 07:49:34 -07001747 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001748 return true;
1749 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001750
reed1f836ee2014-07-07 07:49:34 -07001751 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001752 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001753 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001754 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001755 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001756 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001757
reed@android.coma380ae42009-07-21 01:17:02 +00001758 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001759 // TODO: should we use | instead, or compare all 4 at once?
1760 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001761 return true;
1762 }
reed@google.comc0784db2013-12-13 21:16:12 +00001763 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001764 return true;
1765 }
1766 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001767 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001768}
1769
reed@google.com3b3e8952012-08-16 20:53:31 +00001770bool SkCanvas::quickReject(const SkPath& path) const {
1771 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001772}
1773
reed@google.com3b3e8952012-08-16 20:53:31 +00001774bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001775 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001776 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001777 return false;
1778 }
1779
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001780 SkMatrix inverse;
1781 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001782 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001783 if (bounds) {
1784 bounds->setEmpty();
1785 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001786 return false;
1787 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001788
bsalomon49f085d2014-09-05 13:34:00 -07001789 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001790 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001791 // adjust it outwards in case we are antialiasing
1792 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001793
reed@google.com8f4d2302013-12-17 16:44:46 +00001794 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1795 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796 inverse.mapRect(bounds, r);
1797 }
1798 return true;
1799}
1800
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001801bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001802 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001803 if (clip.isEmpty()) {
1804 if (bounds) {
1805 bounds->setEmpty();
1806 }
1807 return false;
1808 }
1809
bsalomon49f085d2014-09-05 13:34:00 -07001810 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001811 *bounds = clip.getBounds();
1812 }
1813 return true;
1814}
1815
reed@android.com8a1c16f2008-12-17 15:59:43 +00001816const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001817 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001818}
1819
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001820const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001821 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001822}
1823
reed@google.com9c135db2014-03-12 18:28:35 +00001824GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1825 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001826 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001827}
1828
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001829GrContext* SkCanvas::getGrContext() {
1830#if SK_SUPPORT_GPU
1831 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001832 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001833 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001834 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001835 return renderTarget->getContext();
1836 }
1837 }
1838#endif
1839
halcanary96fcdcc2015-08-27 07:41:13 -07001840 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001841
1842}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001843
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001844void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1845 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001846 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001847 if (outer.isEmpty()) {
1848 return;
1849 }
1850 if (inner.isEmpty()) {
1851 this->drawRRect(outer, paint);
1852 return;
1853 }
1854
1855 // We don't have this method (yet), but technically this is what we should
1856 // be able to assert...
1857 // SkASSERT(outer.contains(inner));
1858 //
1859 // For now at least check for containment of bounds
1860 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1861
1862 this->onDrawDRRect(outer, inner, paint);
1863}
1864
reed41af9662015-01-05 07:49:08 -08001865// These need to stop being virtual -- clients need to override the onDraw... versions
1866
1867void SkCanvas::drawPaint(const SkPaint& paint) {
1868 this->onDrawPaint(paint);
1869}
1870
1871void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1872 this->onDrawRect(r, paint);
1873}
1874
1875void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1876 this->onDrawOval(r, paint);
1877}
1878
1879void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1880 this->onDrawRRect(rrect, paint);
1881}
1882
1883void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1884 this->onDrawPoints(mode, count, pts, paint);
1885}
1886
1887void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1888 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1889 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1890 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1891 indices, indexCount, paint);
1892}
1893
1894void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1895 this->onDrawPath(path, paint);
1896}
1897
reeda85d4d02015-05-06 12:56:48 -07001898void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001899 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001900 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001901}
1902
reede47829b2015-08-06 10:02:53 -07001903void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1904 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001905 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001906 if (dst.isEmpty() || src.isEmpty()) {
1907 return;
1908 }
1909 this->onDrawImageRect(image, &src, dst, paint, constraint);
1910}
reed41af9662015-01-05 07:49:08 -08001911
reed84984ef2015-07-17 07:09:43 -07001912void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1913 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001914 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001915 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001916}
1917
reede47829b2015-08-06 10:02:53 -07001918void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1919 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001920 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001921 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1922 constraint);
1923}
reede47829b2015-08-06 10:02:53 -07001924
reed4c21dc52015-06-25 12:32:03 -07001925void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1926 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001927 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001928 if (dst.isEmpty()) {
1929 return;
1930 }
1931 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001932 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001933 }
1934 this->onDrawImageNine(image, center, dst, paint);
1935}
1936
reed41af9662015-01-05 07:49:08 -08001937void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001938 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001939 return;
1940 }
reed41af9662015-01-05 07:49:08 -08001941 this->onDrawBitmap(bitmap, dx, dy, paint);
1942}
1943
reede47829b2015-08-06 10:02:53 -07001944void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001945 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001946 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001947 return;
1948 }
reede47829b2015-08-06 10:02:53 -07001949 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001950}
1951
reed84984ef2015-07-17 07:09:43 -07001952void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1953 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001954 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001955}
1956
reede47829b2015-08-06 10:02:53 -07001957void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1958 SrcRectConstraint constraint) {
1959 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1960 constraint);
1961}
reede47829b2015-08-06 10:02:53 -07001962
reed41af9662015-01-05 07:49:08 -08001963void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1964 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001965 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001966 return;
1967 }
reed4c21dc52015-06-25 12:32:03 -07001968 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001969 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001970 }
reed41af9662015-01-05 07:49:08 -08001971 this->onDrawBitmapNine(bitmap, center, dst, paint);
1972}
1973
reed71c3c762015-06-24 10:29:17 -07001974void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1975 const SkColor colors[], int count, SkXfermode::Mode mode,
1976 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001977 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001978 if (count <= 0) {
1979 return;
1980 }
1981 SkASSERT(atlas);
1982 SkASSERT(xform);
1983 SkASSERT(tex);
1984 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1985}
1986
reedf70b5312016-03-04 16:36:20 -08001987void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1988 if (key) {
1989 this->onDrawAnnotation(rect, key, value);
1990 }
1991}
1992
reede47829b2015-08-06 10:02:53 -07001993void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1994 const SkPaint* paint, SrcRectConstraint constraint) {
1995 if (src) {
1996 this->drawImageRect(image, *src, dst, paint, constraint);
1997 } else {
1998 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1999 dst, paint, constraint);
2000 }
2001}
2002void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2003 const SkPaint* paint, SrcRectConstraint constraint) {
2004 if (src) {
2005 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2006 } else {
2007 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2008 dst, paint, constraint);
2009 }
2010}
2011
reed@android.com8a1c16f2008-12-17 15:59:43 +00002012//////////////////////////////////////////////////////////////////////////////
2013// These are the virtual drawing methods
2014//////////////////////////////////////////////////////////////////////////////
2015
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002016void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002017 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002018 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2019 }
2020}
2021
reed41af9662015-01-05 07:49:08 -08002022void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002023 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002024 this->internalDrawPaint(paint);
2025}
2026
2027void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002028 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002029
2030 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002031 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002032 }
2033
reed@google.com4e2b3d32011-04-07 14:18:59 +00002034 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002035}
2036
reed41af9662015-01-05 07:49:08 -08002037void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2038 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002039 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002040 if ((long)count <= 0) {
2041 return;
2042 }
2043
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002044 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002045 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002046 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002047 // special-case 2 points (common for drawing a single line)
2048 if (2 == count) {
2049 r.set(pts[0], pts[1]);
2050 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002051 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002052 }
senorblanco87e066e2015-10-28 11:23:36 -07002053 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2054 return;
2055 }
2056 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002057 }
reed@google.coma584aed2012-05-16 14:06:02 +00002058
halcanary96fcdcc2015-08-27 07:41:13 -07002059 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002060
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002061 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002062
reed@android.com8a1c16f2008-12-17 15:59:43 +00002063 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002064 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002065 }
reed@google.com4b226022011-01-11 18:32:13 +00002066
reed@google.com4e2b3d32011-04-07 14:18:59 +00002067 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002068}
2069
reed41af9662015-01-05 07:49:08 -08002070void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002071 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002072 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002073 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002074 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002075 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2076 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2077 SkRect tmp(r);
2078 tmp.sort();
2079
senorblanco87e066e2015-10-28 11:23:36 -07002080 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2081 return;
2082 }
2083 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002084 }
reed@google.com4b226022011-01-11 18:32:13 +00002085
reedc83a2972015-07-16 07:40:45 -07002086 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002087
2088 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002089 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002090 }
2091
reed@google.com4e2b3d32011-04-07 14:18:59 +00002092 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093}
2094
reed41af9662015-01-05 07:49:08 -08002095void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002096 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002097 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002098 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002099 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002100 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2101 return;
2102 }
2103 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002104 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002105
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002106 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002107
2108 while (iter.next()) {
2109 iter.fDevice->drawOval(iter, oval, looper.paint());
2110 }
2111
2112 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002113}
2114
reed41af9662015-01-05 07:49:08 -08002115void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002116 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002117 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002118 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002119 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002120 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2121 return;
2122 }
2123 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002124 }
2125
2126 if (rrect.isRect()) {
2127 // call the non-virtual version
2128 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002129 return;
2130 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002131 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002132 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2133 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002134 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002135
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002136 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002137
2138 while (iter.next()) {
2139 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2140 }
2141
2142 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002143}
2144
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002145void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2146 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002147 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002148 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002149 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002150 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2151 return;
2152 }
2153 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002154 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002155
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002156 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002157
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002158 while (iter.next()) {
2159 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2160 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002161
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002162 LOOPER_END
2163}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002164
reed41af9662015-01-05 07:49:08 -08002165void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002166 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002167 if (!path.isFinite()) {
2168 return;
2169 }
2170
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002171 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002172 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002173 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002174 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002175 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2176 return;
2177 }
2178 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002179 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002180
2181 const SkRect& r = path.getBounds();
2182 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002183 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002184 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002185 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002186 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002187 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002188
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002189 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002190
2191 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002192 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002193 }
2194
reed@google.com4e2b3d32011-04-07 14:18:59 +00002195 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002196}
2197
reed262a71b2015-12-05 13:07:27 -08002198bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002199 if (!paint.getImageFilter()) {
2200 return false;
2201 }
2202
2203 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002204 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002205 return false;
2206 }
2207
2208 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2209 // Once we can filter and the filter will return a result larger than itself, we should be
2210 // able to remove this constraint.
2211 // skbug.com/4526
2212 //
2213 SkPoint pt;
2214 ctm.mapXY(x, y, &pt);
2215 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2216 return ir.contains(fMCRec->fRasterClip.getBounds());
2217}
2218
reeda85d4d02015-05-06 12:56:48 -07002219void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002220 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002221 SkRect bounds = SkRect::MakeXYWH(x, y,
2222 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002223 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002224 SkRect tmp = bounds;
2225 if (paint) {
2226 paint->computeFastBounds(tmp, &tmp);
2227 }
2228 if (this->quickReject(tmp)) {
2229 return;
2230 }
reeda85d4d02015-05-06 12:56:48 -07002231 }
2232
2233 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002234 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002235 paint = lazy.init();
2236 }
reed262a71b2015-12-05 13:07:27 -08002237
reed129ed1c2016-02-22 06:42:31 -08002238 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2239 *paint);
2240 if (drawAsSprite && paint->getImageFilter()) {
2241 SkBitmap bitmap;
2242 if (!as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2243 drawAsSprite = false;
2244 } else{
2245 // Until imagefilters are updated, they cannot handle any src type but N32...
2246 if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) {
2247 drawAsSprite = false;
2248 }
2249 }
2250 }
2251
reed262a71b2015-12-05 13:07:27 -08002252 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2253
reeda85d4d02015-05-06 12:56:48 -07002254 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002255 const SkPaint& pnt = looper.paint();
2256 if (drawAsSprite && pnt.getImageFilter()) {
2257 SkBitmap bitmap;
2258 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2259 SkPoint pt;
2260 iter.fMatrix->mapXY(x, y, &pt);
2261 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2262 SkScalarRoundToInt(pt.fX),
2263 SkScalarRoundToInt(pt.fY), pnt);
2264 }
2265 } else {
2266 iter.fDevice->drawImage(iter, image, x, y, pnt);
2267 }
reeda85d4d02015-05-06 12:56:48 -07002268 }
2269
2270 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002271}
2272
reed41af9662015-01-05 07:49:08 -08002273void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002274 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002275 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002276 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002277 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002278 if (paint) {
2279 paint->computeFastBounds(dst, &storage);
2280 }
2281 if (this->quickReject(storage)) {
2282 return;
2283 }
reeda85d4d02015-05-06 12:56:48 -07002284 }
2285 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002286 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002287 paint = lazy.init();
2288 }
2289
senorblancoc41e7e12015-12-07 12:51:30 -08002290 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002291 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002292
2293 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002294 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002295 }
2296
2297 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002298}
2299
reed41af9662015-01-05 07:49:08 -08002300void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002301 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302 SkDEBUGCODE(bitmap.validate();)
2303
reed33366972015-10-08 09:22:02 -07002304 if (bitmap.drawsNothing()) {
2305 return;
2306 }
2307
2308 SkLazyPaint lazy;
2309 if (nullptr == paint) {
2310 paint = lazy.init();
2311 }
2312
2313 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2314
2315 SkRect storage;
2316 const SkRect* bounds = nullptr;
2317 if (paint->canComputeFastBounds()) {
2318 bitmap.getBounds(&storage);
2319 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002320 SkRect tmp = storage;
2321 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2322 return;
2323 }
2324 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002325 }
reed@google.com4b226022011-01-11 18:32:13 +00002326
reed129ed1c2016-02-22 06:42:31 -08002327 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2328 *paint);
2329 if (drawAsSprite && paint->getImageFilter()) {
2330 // Until imagefilters are updated, they cannot handle any src type but N32...
2331 if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) {
2332 drawAsSprite = false;
2333 }
2334 }
2335
reed262a71b2015-12-05 13:07:27 -08002336 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002337
2338 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002339 const SkPaint& pnt = looper.paint();
2340 if (drawAsSprite && pnt.getImageFilter()) {
2341 SkPoint pt;
2342 iter.fMatrix->mapXY(x, y, &pt);
2343 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2344 SkScalarRoundToInt(pt.fX),
2345 SkScalarRoundToInt(pt.fY), pnt);
2346 } else {
2347 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2348 }
reed33366972015-10-08 09:22:02 -07002349 }
reed262a71b2015-12-05 13:07:27 -08002350
reed33366972015-10-08 09:22:02 -07002351 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352}
2353
reed@google.com9987ec32011-09-07 11:57:52 +00002354// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002355void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002356 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002357 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002358 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002359 return;
2360 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002361
halcanary96fcdcc2015-08-27 07:41:13 -07002362 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002363 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002364 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2365 return;
2366 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002367 }
reed@google.com3d608122011-11-21 15:16:16 +00002368
reed@google.com33535f32012-09-25 15:37:50 +00002369 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002370 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002371 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002372 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002373
senorblancoc41e7e12015-12-07 12:51:30 -08002374 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002375 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002376
reed@google.com33535f32012-09-25 15:37:50 +00002377 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002378 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002379 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002380
reed@google.com33535f32012-09-25 15:37:50 +00002381 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002382}
2383
reed41af9662015-01-05 07:49:08 -08002384void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002385 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002387 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002388 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002389}
2390
reed4c21dc52015-06-25 12:32:03 -07002391void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2392 const SkPaint* paint) {
2393 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2394
halcanary96fcdcc2015-08-27 07:41:13 -07002395 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002396 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002397 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2398 return;
2399 }
reed@google.com3d608122011-11-21 15:16:16 +00002400 }
reed4c21dc52015-06-25 12:32:03 -07002401
2402 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002403 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002404 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002405 }
reed4c21dc52015-06-25 12:32:03 -07002406
senorblancoc41e7e12015-12-07 12:51:30 -08002407 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002408
2409 while (iter.next()) {
2410 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002411 }
reed4c21dc52015-06-25 12:32:03 -07002412
2413 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002414}
2415
reed41af9662015-01-05 07:49:08 -08002416void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2417 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002418 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002419 SkDEBUGCODE(bitmap.validate();)
2420
halcanary96fcdcc2015-08-27 07:41:13 -07002421 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002422 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002423 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2424 return;
2425 }
reed4c21dc52015-06-25 12:32:03 -07002426 }
2427
2428 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002429 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002430 paint = lazy.init();
2431 }
2432
senorblancoc41e7e12015-12-07 12:51:30 -08002433 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002434
2435 while (iter.next()) {
2436 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2437 }
2438
2439 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002440}
2441
reed@google.comf67e4cf2011-03-15 20:56:58 +00002442class SkDeviceFilteredPaint {
2443public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002444 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002445 uint32_t filteredFlags = device->filterTextFlags(paint);
2446 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002447 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002448 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002449 fPaint = newPaint;
2450 } else {
2451 fPaint = &paint;
2452 }
2453 }
2454
reed@google.comf67e4cf2011-03-15 20:56:58 +00002455 const SkPaint& paint() const { return *fPaint; }
2456
2457private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002458 const SkPaint* fPaint;
2459 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002460};
2461
bungeman@google.com52c748b2011-08-22 21:30:43 +00002462void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2463 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002464 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002465 draw.fDevice->drawRect(draw, r, paint);
2466 } else {
2467 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002468 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002469 draw.fDevice->drawRect(draw, r, p);
2470 }
2471}
2472
2473void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2474 const char text[], size_t byteLength,
2475 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002476 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002477
2478 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002479 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002480 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002481 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002482 return;
2483 }
2484
2485 SkScalar width = 0;
2486 SkPoint start;
2487
2488 start.set(0, 0); // to avoid warning
2489 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2490 SkPaint::kStrikeThruText_Flag)) {
2491 width = paint.measureText(text, byteLength);
2492
2493 SkScalar offsetX = 0;
2494 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2495 offsetX = SkScalarHalf(width);
2496 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2497 offsetX = width;
2498 }
2499 start.set(x - offsetX, y);
2500 }
2501
2502 if (0 == width) {
2503 return;
2504 }
2505
2506 uint32_t flags = paint.getFlags();
2507
2508 if (flags & (SkPaint::kUnderlineText_Flag |
2509 SkPaint::kStrikeThruText_Flag)) {
2510 SkScalar textSize = paint.getTextSize();
2511 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2512 SkRect r;
2513
2514 r.fLeft = start.fX;
2515 r.fRight = start.fX + width;
2516
2517 if (flags & SkPaint::kUnderlineText_Flag) {
2518 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2519 start.fY);
2520 r.fTop = offset;
2521 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002522 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002523 }
2524 if (flags & SkPaint::kStrikeThruText_Flag) {
2525 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2526 start.fY);
2527 r.fTop = offset;
2528 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002529 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002530 }
2531 }
2532}
2533
reed@google.come0d9ce82014-04-23 04:00:17 +00002534void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2535 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002536 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002537
2538 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002539 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002540 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002541 DrawTextDecorations(iter, dfp.paint(),
2542 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543 }
2544
reed@google.com4e2b3d32011-04-07 14:18:59 +00002545 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002546}
2547
reed@google.come0d9ce82014-04-23 04:00:17 +00002548void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2549 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002550 SkPoint textOffset = SkPoint::Make(0, 0);
2551
halcanary96fcdcc2015-08-27 07:41:13 -07002552 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002553
reed@android.com8a1c16f2008-12-17 15:59:43 +00002554 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002555 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002556 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002557 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002558 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002559
reed@google.com4e2b3d32011-04-07 14:18:59 +00002560 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002561}
2562
reed@google.come0d9ce82014-04-23 04:00:17 +00002563void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2564 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002565
2566 SkPoint textOffset = SkPoint::Make(0, constY);
2567
halcanary96fcdcc2015-08-27 07:41:13 -07002568 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002569
reed@android.com8a1c16f2008-12-17 15:59:43 +00002570 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002571 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002572 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002573 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002574 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002575
reed@google.com4e2b3d32011-04-07 14:18:59 +00002576 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002577}
2578
reed@google.come0d9ce82014-04-23 04:00:17 +00002579void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2580 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002581 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002582
reed@android.com8a1c16f2008-12-17 15:59:43 +00002583 while (iter.next()) {
2584 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002585 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002586 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002587
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002588 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002589}
2590
fmalita00d5c2c2014-08-21 08:53:26 -07002591void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2592 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002593
fmalita85d5eb92015-03-04 11:20:12 -08002594 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002595 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002596 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002597 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002598 SkRect tmp;
2599 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2600 return;
2601 }
2602 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002603 }
2604
fmalita024f9962015-03-03 19:08:17 -08002605 // We cannot filter in the looper as we normally do, because the paint is
2606 // incomplete at this point (text-related attributes are embedded within blob run paints).
2607 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002608 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002609
fmalita85d5eb92015-03-04 11:20:12 -08002610 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002611
fmalitaaa1b9122014-08-28 14:32:24 -07002612 while (iter.next()) {
2613 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002614 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002615 }
2616
fmalitaaa1b9122014-08-28 14:32:24 -07002617 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002618
2619 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002620}
2621
reed@google.come0d9ce82014-04-23 04:00:17 +00002622// These will become non-virtual, so they always call the (virtual) onDraw... method
2623void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2624 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002625 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002626 this->onDrawText(text, byteLength, x, y, paint);
2627}
2628void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2629 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002630 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002631 this->onDrawPosText(text, byteLength, pos, paint);
2632}
2633void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2634 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002635 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002636 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2637}
2638void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2639 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002640 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002641 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2642}
fmalita00d5c2c2014-08-21 08:53:26 -07002643void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2644 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002645 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002646 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002647 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002648}
reed@google.come0d9ce82014-04-23 04:00:17 +00002649
reed41af9662015-01-05 07:49:08 -08002650void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2651 const SkPoint verts[], const SkPoint texs[],
2652 const SkColor colors[], SkXfermode* xmode,
2653 const uint16_t indices[], int indexCount,
2654 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002655 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002656 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002657
reed@android.com8a1c16f2008-12-17 15:59:43 +00002658 while (iter.next()) {
2659 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002660 colors, xmode, indices, indexCount,
2661 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002662 }
reed@google.com4b226022011-01-11 18:32:13 +00002663
reed@google.com4e2b3d32011-04-07 14:18:59 +00002664 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002665}
2666
dandovb3c9d1c2014-08-12 08:34:29 -07002667void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2668 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002669 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002670 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002671 return;
2672 }
mtklein6cfa73a2014-08-13 13:33:49 -07002673
dandovecfff212014-08-04 10:02:00 -07002674 // Since a patch is always within the convex hull of the control points, we discard it when its
2675 // bounding rectangle is completely outside the current clip.
2676 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002677 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002678 if (this->quickReject(bounds)) {
2679 return;
2680 }
mtklein6cfa73a2014-08-13 13:33:49 -07002681
dandovb3c9d1c2014-08-12 08:34:29 -07002682 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2683}
2684
2685void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2686 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2687
halcanary96fcdcc2015-08-27 07:41:13 -07002688 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002689
dandovecfff212014-08-04 10:02:00 -07002690 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002691 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002692 }
mtklein6cfa73a2014-08-13 13:33:49 -07002693
dandovecfff212014-08-04 10:02:00 -07002694 LOOPER_END
2695}
2696
reeda8db7282015-07-07 10:22:31 -07002697void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002698 RETURN_ON_NULL(dr);
2699 if (x || y) {
2700 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2701 this->onDrawDrawable(dr, &matrix);
2702 } else {
2703 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002704 }
2705}
2706
reeda8db7282015-07-07 10:22:31 -07002707void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002708 RETURN_ON_NULL(dr);
2709 if (matrix && matrix->isIdentity()) {
2710 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002711 }
reede3b38ce2016-01-08 09:18:44 -08002712 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002713}
2714
2715void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2716 SkRect bounds = dr->getBounds();
2717 if (matrix) {
2718 matrix->mapRect(&bounds);
2719 }
2720 if (this->quickReject(bounds)) {
2721 return;
2722 }
2723 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002724}
2725
reed71c3c762015-06-24 10:29:17 -07002726void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2727 const SkColor colors[], int count, SkXfermode::Mode mode,
2728 const SkRect* cull, const SkPaint* paint) {
2729 if (cull && this->quickReject(*cull)) {
2730 return;
2731 }
2732
2733 SkPaint pnt;
2734 if (paint) {
2735 pnt = *paint;
2736 }
2737
halcanary96fcdcc2015-08-27 07:41:13 -07002738 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002739 while (iter.next()) {
2740 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2741 }
2742 LOOPER_END
2743}
2744
reedf70b5312016-03-04 16:36:20 -08002745void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2746 SkASSERT(key);
2747
2748 SkPaint paint;
2749 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2750 while (iter.next()) {
2751 iter.fDevice->drawAnnotation(iter, rect, key, value);
2752 }
2753 LOOPER_END
2754}
2755
reed@android.com8a1c16f2008-12-17 15:59:43 +00002756//////////////////////////////////////////////////////////////////////////////
2757// These methods are NOT virtual, and therefore must call back into virtual
2758// methods, rather than actually drawing themselves.
2759//////////////////////////////////////////////////////////////////////////////
2760
2761void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002762 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002763 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764 SkPaint paint;
2765
2766 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002767 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002768 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769 }
2770 this->drawPaint(paint);
2771}
2772
reed@android.com845fdac2009-06-23 03:01:32 +00002773void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002774 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775 SkPaint paint;
2776
2777 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002778 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002779 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780 }
2781 this->drawPaint(paint);
2782}
2783
2784void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002785 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002787
reed@android.com8a1c16f2008-12-17 15:59:43 +00002788 pt.set(x, y);
2789 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2790}
2791
2792void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794 SkPoint pt;
2795 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002796
reed@android.com8a1c16f2008-12-17 15:59:43 +00002797 pt.set(x, y);
2798 paint.setColor(color);
2799 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2800}
2801
2802void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2803 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002804 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002806
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807 pts[0].set(x0, y0);
2808 pts[1].set(x1, y1);
2809 this->drawPoints(kLines_PointMode, 2, pts, paint);
2810}
2811
2812void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2813 SkScalar right, SkScalar bottom,
2814 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816 SkRect r;
2817
2818 r.set(left, top, right, bottom);
2819 this->drawRect(r, paint);
2820}
2821
2822void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2823 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002824 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825 if (radius < 0) {
2826 radius = 0;
2827 }
2828
2829 SkRect r;
2830 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002831 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002832}
2833
2834void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2835 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002836 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837 if (rx > 0 && ry > 0) {
2838 if (paint.canComputeFastBounds()) {
2839 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002840 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002841 return;
2842 }
2843 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002844 SkRRect rrect;
2845 rrect.setRectXY(r, rx, ry);
2846 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847 } else {
2848 this->drawRect(r, paint);
2849 }
2850}
2851
reed@android.com8a1c16f2008-12-17 15:59:43 +00002852void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2853 SkScalar sweepAngle, bool useCenter,
2854 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002855 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002856 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2857 this->drawOval(oval, paint);
2858 } else {
2859 SkPath path;
2860 if (useCenter) {
2861 path.moveTo(oval.centerX(), oval.centerY());
2862 }
2863 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2864 if (useCenter) {
2865 path.close();
2866 }
2867 this->drawPath(path, paint);
2868 }
2869}
2870
2871void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2872 const SkPath& path, SkScalar hOffset,
2873 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002874 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002875 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002876
reed@android.com8a1c16f2008-12-17 15:59:43 +00002877 matrix.setTranslate(hOffset, vOffset);
2878 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2879}
2880
reed@android.comf76bacf2009-05-13 14:00:33 +00002881///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002882
2883/**
2884 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2885 * against the playback cost of recursing into the subpicture to get at its actual ops.
2886 *
2887 * For now we pick a conservatively small value, though measurement (and other heuristics like
2888 * the type of ops contained) may justify changing this value.
2889 */
2890#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002891
reedd5fa1a42014-08-09 11:08:05 -07002892void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002893 RETURN_ON_NULL(picture);
2894
reed1c2c4412015-04-30 13:09:24 -07002895 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002896 if (matrix && matrix->isIdentity()) {
2897 matrix = nullptr;
2898 }
2899 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2900 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2901 picture->playback(this);
2902 } else {
2903 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002904 }
2905}
robertphillips9b14f262014-06-04 05:40:44 -07002906
reedd5fa1a42014-08-09 11:08:05 -07002907void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2908 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002909 if (!paint || paint->canComputeFastBounds()) {
2910 SkRect bounds = picture->cullRect();
2911 if (paint) {
2912 paint->computeFastBounds(bounds, &bounds);
2913 }
2914 if (matrix) {
2915 matrix->mapRect(&bounds);
2916 }
2917 if (this->quickReject(bounds)) {
2918 return;
2919 }
2920 }
2921
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002922 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002923 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002924 // Canvas has to first give the device the opportunity to render
2925 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002926 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002927 return; // the device has rendered the entire picture
2928 }
2929 }
2930
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002931 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002932 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002933}
2934
reed@android.com8a1c16f2008-12-17 15:59:43 +00002935///////////////////////////////////////////////////////////////////////////////
2936///////////////////////////////////////////////////////////////////////////////
2937
2938SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002939 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002940
2941 SkASSERT(canvas);
2942
2943 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2944 fDone = !fImpl->next();
2945}
2946
2947SkCanvas::LayerIter::~LayerIter() {
2948 fImpl->~SkDrawIter();
2949}
2950
2951void SkCanvas::LayerIter::next() {
2952 fDone = !fImpl->next();
2953}
2954
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002955SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002956 return fImpl->getDevice();
2957}
2958
2959const SkMatrix& SkCanvas::LayerIter::matrix() const {
2960 return fImpl->getMatrix();
2961}
2962
2963const SkPaint& SkCanvas::LayerIter::paint() const {
2964 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002965 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002966 paint = &fDefaultPaint;
2967 }
2968 return *paint;
2969}
2970
2971const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2972int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2973int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002974
2975///////////////////////////////////////////////////////////////////////////////
2976
fmalitac3b589a2014-06-05 12:40:07 -07002977SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002978
2979///////////////////////////////////////////////////////////////////////////////
2980
2981static bool supported_for_raster_canvas(const SkImageInfo& info) {
2982 switch (info.alphaType()) {
2983 case kPremul_SkAlphaType:
2984 case kOpaque_SkAlphaType:
2985 break;
2986 default:
2987 return false;
2988 }
2989
2990 switch (info.colorType()) {
2991 case kAlpha_8_SkColorType:
2992 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002993 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002994 break;
2995 default:
2996 return false;
2997 }
2998
2999 return true;
3000}
3001
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003002SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3003 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003004 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003005 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003006
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003007 SkBitmap bitmap;
3008 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003009 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003010 }
halcanary385fe4d2015-08-26 13:07:48 -07003011 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003012}
reedd5fa1a42014-08-09 11:08:05 -07003013
3014///////////////////////////////////////////////////////////////////////////////
3015
3016SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003017 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003018 : fCanvas(canvas)
3019 , fSaveCount(canvas->getSaveCount())
3020{
bsalomon49f085d2014-09-05 13:34:00 -07003021 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003022 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003023 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003024 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003025 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003026 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003027 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003028 canvas->save();
3029 }
mtklein6cfa73a2014-08-13 13:33:49 -07003030
bsalomon49f085d2014-09-05 13:34:00 -07003031 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003032 canvas->concat(*matrix);
3033 }
3034}
3035
3036SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3037 fCanvas->restoreToCount(fSaveCount);
3038}