blob: d2d7c5925a04e8960f2b4376b520404bc1e26ff5 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
bungemand3ebb482015-08-05 13:57:49 -07008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
bungemand3ebb482015-08-05 13:57:49 -070013#include "SkDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080018#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070019#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080020#include "SkImage_Base.h"
21#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000022#include "SkMetaData.h"
reed4c21dc52015-06-25 12:32:03 -070023#include "SkNinePatchIter.h"
reedc83a2972015-07-16 07:40:45 -070024#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070025#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000026#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000027#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080028#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000029#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000030#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000031#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070032#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000033#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000034#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080035#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070036
37#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000039#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080040#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000041#include "GrRenderTarget.h"
robertphillips7354a4b2015-12-16 05:08:27 -080042#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000043#endif
44
reede3b38ce2016-01-08 09:18:44 -080045#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
46
reedc83a2972015-07-16 07:40:45 -070047/*
48 * Return true if the drawing this rect would hit every pixels in the canvas.
49 *
50 * Returns false if
51 * - rect does not contain the canvas' bounds
52 * - paint is not fill
53 * - paint would blur or otherwise change the coverage of the rect
54 */
55bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
56 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070057 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
58 (int)kNone_ShaderOverrideOpacity,
59 "need_matching_enums0");
60 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
61 (int)kOpaque_ShaderOverrideOpacity,
62 "need_matching_enums1");
63 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
64 (int)kNotOpaque_ShaderOverrideOpacity,
65 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070066
67 const SkISize size = this->getBaseLayerSize();
68 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
69 if (!this->getClipStack()->quickContains(bounds)) {
70 return false;
71 }
72
73 if (rect) {
74 if (!this->getTotalMatrix().rectStaysRect()) {
75 return false; // conservative
76 }
77
78 SkRect devRect;
79 this->getTotalMatrix().mapRect(&devRect, *rect);
fmalita8c0144c2015-07-22 05:56:16 -070080 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070081 return false;
82 }
83 }
84
85 if (paint) {
86 SkPaint::Style paintStyle = paint->getStyle();
87 if (!(paintStyle == SkPaint::kFill_Style ||
88 paintStyle == SkPaint::kStrokeAndFill_Style)) {
89 return false;
90 }
91 if (paint->getMaskFilter() || paint->getLooper()
92 || paint->getPathEffect() || paint->getImageFilter()) {
93 return false; // conservative
94 }
95 }
96 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
97}
98
99///////////////////////////////////////////////////////////////////////////////////////////////////
100
reedd990e2f2014-12-22 11:58:30 -0800101static bool gIgnoreSaveLayerBounds;
102void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
103 gIgnoreSaveLayerBounds = ignore;
104}
105bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
106 return gIgnoreSaveLayerBounds;
107}
108
reed0acf1b42014-12-22 16:12:38 -0800109static bool gTreatSpriteAsBitmap;
110void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
111 gTreatSpriteAsBitmap = spriteAsBitmap;
112}
113bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
114 return gTreatSpriteAsBitmap;
115}
116
reed@google.comda17f752012-08-16 18:27:05 +0000117// experimental for faster tiled drawing...
118//#define SK_ENABLE_CLIP_QUICKREJECT
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119//#define SK_TRACE_SAVERESTORE
120
121#ifdef SK_TRACE_SAVERESTORE
122 static int gLayerCounter;
123 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
124 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
125
126 static int gRecCounter;
127 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
128 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
129
130 static int gCanvasCounter;
131 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
132 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
133#else
134 #define inc_layer()
135 #define dec_layer()
136 #define inc_rec()
137 #define dec_rec()
138 #define inc_canvas()
139 #define dec_canvas()
140#endif
141
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000142typedef SkTLazy<SkPaint> SkLazyPaint;
143
reedc83a2972015-07-16 07:40:45 -0700144void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000145 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700146 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
147 ? SkSurface::kDiscard_ContentChangeMode
148 : SkSurface::kRetain_ContentChangeMode);
149 }
150}
151
152void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
153 ShaderOverrideOpacity overrideOpacity) {
154 if (fSurfaceBase) {
155 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
156 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
157 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
158 // and therefore we don't care which mode we're in.
159 //
160 if (fSurfaceBase->outstandingImageSnapshot()) {
161 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
162 mode = SkSurface::kDiscard_ContentChangeMode;
163 }
164 }
165 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000166 }
167}
168
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170
reed4a8126e2014-09-22 07:29:03 -0700171static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
172 const uint32_t propFlags = props.flags();
173 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
174 flags &= ~SkPaint::kDither_Flag;
175 }
176 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
177 flags &= ~SkPaint::kAntiAlias_Flag;
178 }
179 return flags;
180}
181
182///////////////////////////////////////////////////////////////////////////////
183
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000184/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 The clip/matrix/proc are fields that reflect the top of the save/restore
186 stack. Whenever the canvas changes, it marks a dirty flag, and then before
187 these are used (assuming we're not on a layer) we rebuild these cache
188 values: they reflect the top of the save stack, but translated and clipped
189 by the device's XY offset and bitmap-bounds.
190*/
191struct DeviceCM {
192 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000193 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000194 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000195 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700196 const SkMatrix* fMatrix;
197 SkMatrix fMatrixStorage;
198 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199
reed96e657d2015-03-10 17:30:07 -0700200 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed86a17e72015-05-14 12:25:22 -0700201 bool conservativeRasterClip, bool deviceIsBitmapDevice)
halcanary96fcdcc2015-08-27 07:41:13 -0700202 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700203 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700204 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700205 {
halcanary96fcdcc2015-08-27 07:41:13 -0700206 if (nullptr != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000208 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 }
reed@google.com4b226022011-01-11 18:32:13 +0000210 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700211 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000212 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000214 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700215 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000216 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 fDevice->unref();
218 }
halcanary385fe4d2015-08-26 13:07:48 -0700219 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000220 }
reed@google.com4b226022011-01-11 18:32:13 +0000221
mtkleinfeaadee2015-04-08 11:25:48 -0700222 void reset(const SkIRect& bounds) {
223 SkASSERT(!fPaint);
224 SkASSERT(!fNext);
225 SkASSERT(fDevice);
226 fClip.setRect(bounds);
227 }
228
reed@google.com045e62d2011-10-24 12:19:46 +0000229 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
230 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000231 int x = fDevice->getOrigin().x();
232 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 int width = fDevice->width();
234 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000235
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 if ((x | y) == 0) {
237 fMatrix = &totalMatrix;
238 fClip = totalClip;
239 } else {
240 fMatrixStorage = totalMatrix;
241 fMatrixStorage.postTranslate(SkIntToScalar(-x),
242 SkIntToScalar(-y));
243 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 totalClip.translate(-x, -y, &fClip);
246 }
247
reed@google.com045e62d2011-10-24 12:19:46 +0000248 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249
250 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000251
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000253 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 SkRegion::kDifference_Op);
255 }
reed@google.com4b226022011-01-11 18:32:13 +0000256
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000257 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
258
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259#ifdef SK_DEBUG
260 if (!fClip.isEmpty()) {
261 SkIRect deviceR;
262 deviceR.set(0, 0, width, height);
263 SkASSERT(deviceR.contains(fClip.getBounds()));
264 }
265#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000266 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267};
268
269/* This is the record we keep for each save/restore level in the stack.
270 Since a level optionally copies the matrix and/or stack, we have pointers
271 for these fields. If the value is copied for this level, the copy is
272 stored in the ...Storage field, and the pointer points to that. If the
273 value is not copied for this level, we ignore ...Storage, and just point
274 at the corresponding value in the previous level in the stack.
275*/
276class SkCanvas::MCRec {
277public:
reed1f836ee2014-07-07 07:49:34 -0700278 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700279 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 /* If there are any layers in the stack, this points to the top-most
281 one that is at or below this level in the stack (so we know what
282 bitmap/device to draw into from this level. This value is NOT
283 reference counted, since the real owner is either our fLayer field,
284 or a previous one in a lower level.)
285 */
reed2ff1fce2014-12-11 07:07:37 -0800286 DeviceCM* fTopLayer;
287 SkRasterClip fRasterClip;
288 SkMatrix fMatrix;
289 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290
reedd9544982014-09-09 18:46:22 -0700291 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700292 fFilter = nullptr;
293 fLayer = nullptr;
294 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800295 fMatrix.reset();
296 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700297
reedd9544982014-09-09 18:46:22 -0700298 // don't bother initializing fNext
299 inc_rec();
300 }
reed2ff1fce2014-12-11 07:07:37 -0800301 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700302 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700303 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700304 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800305 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700306
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307 // don't bother initializing fNext
308 inc_rec();
309 }
310 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000311 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700312 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 dec_rec();
314 }
mtkleinfeaadee2015-04-08 11:25:48 -0700315
316 void reset(const SkIRect& bounds) {
317 SkASSERT(fLayer);
318 SkASSERT(fDeferredSaveCount == 0);
319
320 fMatrix.reset();
321 fRasterClip.setRect(bounds);
322 fLayer->reset(bounds);
323 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324};
325
326class SkDrawIter : public SkDraw {
327public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000328 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000329 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000330 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 canvas->updateDeviceCMCache();
332
reed687fa1c2015-04-07 08:00:56 -0700333 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000335 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 }
reed@google.com4b226022011-01-11 18:32:13 +0000337
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 bool next() {
339 // skip over recs with empty clips
340 if (fSkipEmptyClips) {
341 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
342 fCurrLayer = fCurrLayer->fNext;
343 }
344 }
345
reed@google.comf68c5e22012-02-24 16:38:58 +0000346 const DeviceCM* rec = fCurrLayer;
347 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348
349 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000350 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
351 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700353 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700354 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700355 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000357 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358
359 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700360 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000361
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 return true;
363 }
364 return false;
365 }
reed@google.com4b226022011-01-11 18:32:13 +0000366
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000367 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000368 int getX() const { return fDevice->getOrigin().x(); }
369 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 const SkMatrix& getMatrix() const { return *fMatrix; }
371 const SkRegion& getClip() const { return *fClip; }
372 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000373
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374private:
375 SkCanvas* fCanvas;
376 const DeviceCM* fCurrLayer;
377 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 SkBool8 fSkipEmptyClips;
379
380 typedef SkDraw INHERITED;
381};
382
383/////////////////////////////////////////////////////////////////////////////
384
reeddbc3cef2015-04-29 12:18:57 -0700385static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
386 return lazy->isValid() ? lazy->get() : lazy->set(orig);
387}
388
389/**
390 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700391 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700392 */
393static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700394 SkImageFilter* imgf = paint.getImageFilter();
395 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700396 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700397 }
398
399 SkColorFilter* imgCF;
400 if (!imgf->asAColorFilter(&imgCF)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700401 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700402 }
403
404 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700405 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700406 // there is no existing paint colorfilter, so we can just return the imagefilter's
407 return imgCF;
408 }
409
410 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
411 // and we need to combine them into a single colorfilter.
412 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
413 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700414}
415
senorblanco87e066e2015-10-28 11:23:36 -0700416/**
417 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
418 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
419 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
420 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
421 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
422 * conservative "effective" bounds based on the settings in the paint... with one exception. This
423 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
424 * deliberately ignored.
425 */
426static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
427 const SkRect& rawBounds,
428 SkRect* storage) {
429 SkPaint tmpUnfiltered(paint);
430 tmpUnfiltered.setImageFilter(nullptr);
431 if (tmpUnfiltered.canComputeFastBounds()) {
432 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
433 } else {
434 return rawBounds;
435 }
436}
437
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438class AutoDrawLooper {
439public:
senorblanco87e066e2015-10-28 11:23:36 -0700440 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
441 // paint. It's used to determine the size of the offscreen layer for filters.
442 // If null, the clip will be used instead.
reed4a8126e2014-09-22 07:29:03 -0700443 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000444 bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700445 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000446 fCanvas = canvas;
fmalita77650002016-01-21 18:47:11 -0800447#ifdef SK_SUPPORT_LEGACY_DRAWFLTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800449#else
450 fFilter = nullptr;
451#endif
reed4a8126e2014-09-22 07:29:03 -0700452 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000453 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700454 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000455 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456
reeddbc3cef2015-04-29 12:18:57 -0700457 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
458 if (simplifiedCF) {
459 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
460 paint->setColorFilter(simplifiedCF)->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700461 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700462 fPaint = paint;
463 }
464
465 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700466 /**
467 * We implement ImageFilters for a given draw by creating a layer, then applying the
468 * imagefilter to the pixels of that layer (its backing surface/image), and then
469 * we call restore() to xfer that layer to the main canvas.
470 *
471 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
472 * 2. Generate the src pixels:
473 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
474 * return (fPaint). We then draw the primitive (using srcover) into a cleared
475 * buffer/surface.
476 * 3. Restore the layer created in #1
477 * The imagefilter is passed the buffer/surface from the layer (now filled with the
478 * src pixels of the primitive). It returns a new "filtered" buffer, which we
479 * draw onto the previous layer using the xfermode from the original paint.
480 */
reed@google.com8926b162012-03-23 15:36:36 +0000481 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700482 tmp.setImageFilter(fPaint->getImageFilter());
483 tmp.setXfermode(fPaint->getXfermode());
senorblanco87e066e2015-10-28 11:23:36 -0700484 SkRect storage;
485 if (rawBounds) {
486 // Make rawBounds include all paint outsets except for those due to image filters.
487 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
488 }
reedbfd5f172016-01-07 11:28:08 -0800489 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700490 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700491 fTempLayerForImageFilter = true;
492 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000493 }
494
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000495 if (SkDrawLooper* looper = paint.getLooper()) {
496 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
497 looper->contextSize());
498 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000499 fIsSimple = false;
500 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700501 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000502 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700503 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000504 }
piotaixrb5fae932014-09-24 13:03:30 -0700505
reed4a8126e2014-09-22 07:29:03 -0700506 uint32_t oldFlags = paint.getFlags();
507 fNewPaintFlags = filter_paint_flags(props, oldFlags);
508 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700509 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700510 paint->setFlags(fNewPaintFlags);
511 fPaint = paint;
512 // if we're not simple, doNext() will take care of calling setFlags()
513 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700517 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000518 fCanvas->internalRestore();
519 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000520 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000522
reed@google.com4e2b3d32011-04-07 14:18:59 +0000523 const SkPaint& paint() const {
524 SkASSERT(fPaint);
525 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000527
reed@google.com129ec222012-05-15 13:24:09 +0000528 bool next(SkDrawFilter::Type drawType) {
529 if (fDone) {
530 return false;
531 } else if (fIsSimple) {
532 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000533 return !fPaint->nothingToDraw();
534 } else {
535 return this->doNext(drawType);
536 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000537 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000538
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539private:
reeddbc3cef2015-04-29 12:18:57 -0700540 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
541 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000542 SkCanvas* fCanvas;
543 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000544 SkDrawFilter* fFilter;
545 const SkPaint* fPaint;
546 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700547 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700548 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000549 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000550 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000551 SkDrawLooper::Context* fLooperContext;
552 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000553
554 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555};
556
reed@google.com129ec222012-05-15 13:24:09 +0000557bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700558 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000559 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700560 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000561
reeddbc3cef2015-04-29 12:18:57 -0700562 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
563 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700564 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000565
reed5c476fb2015-04-20 08:04:21 -0700566 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700567 paint->setImageFilter(nullptr);
568 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000569 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000570
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000571 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000572 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000573 return false;
574 }
575 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000576 if (!fFilter->filter(paint, drawType)) {
577 fDone = true;
578 return false;
579 }
halcanary96fcdcc2015-08-27 07:41:13 -0700580 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000581 // no looper means we only draw once
582 fDone = true;
583 }
584 }
585 fPaint = paint;
586
587 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000588 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000589 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000590 }
591
592 // call this after any possible paint modifiers
593 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700594 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000595 return false;
596 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000597 return true;
598}
599
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600////////// macros to place around the internal draw calls //////////////////
601
reed262a71b2015-12-05 13:07:27 -0800602#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
603 this->predrawNotify(); \
604 AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \
605 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
606 SkDrawIter iter(this);
607
608
reed@google.com8926b162012-03-23 15:36:36 +0000609#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000610 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700611 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000612 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000613 SkDrawIter iter(this);
614
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000615#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000616 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700617 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000618 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000620
reedc83a2972015-07-16 07:40:45 -0700621#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
622 this->predrawNotify(bounds, &paint, auxOpaque); \
623 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
624 while (looper.next(type)) { \
625 SkDrawIter iter(this);
626
reed@google.com4e2b3d32011-04-07 14:18:59 +0000627#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628
629////////////////////////////////////////////////////////////////////////////
630
mtkleinfeaadee2015-04-08 11:25:48 -0700631void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
632 this->restoreToCount(1);
633 fCachedLocalClipBounds.setEmpty();
634 fCachedLocalClipBoundsDirty = true;
635 fClipStack->reset();
636 fMCRec->reset(bounds);
637
638 // We're peering through a lot of structs here. Only at this scope do we
639 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
640 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
641}
642
reedd9544982014-09-09 18:46:22 -0700643SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800644 if (device && device->forceConservativeRasterClip()) {
645 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
646 }
647 // Since init() is only called once by our constructors, it is safe to perform this
648 // const-cast.
649 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
650
reed@google.comc0784db2013-12-13 21:16:12 +0000651 fCachedLocalClipBounds.setEmpty();
652 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000653 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000654 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700655 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800656 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700657 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658
halcanary385fe4d2015-08-26 13:07:48 -0700659 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700660
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700662 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663
reeda499f902015-05-01 09:34:31 -0700664 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
665 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700666 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700667
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669
halcanary96fcdcc2015-08-27 07:41:13 -0700670 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000671
reedf92c8662014-08-18 08:02:43 -0700672 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700673 // The root device and the canvas should always have the same pixel geometry
674 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700675 device->onAttachToCanvas(this);
676 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800677 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700678 }
679 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680}
681
reed@google.comcde92112011-07-06 20:00:52 +0000682SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000683 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700684 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800685 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000686{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000687 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000688
halcanary96fcdcc2015-08-27 07:41:13 -0700689 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000690}
691
reedd9544982014-09-09 18:46:22 -0700692static SkBitmap make_nopixels(int width, int height) {
693 SkBitmap bitmap;
694 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
695 return bitmap;
696}
697
698class SkNoPixelsBitmapDevice : public SkBitmapDevice {
699public:
robertphillipsfcf78292015-06-19 11:49:52 -0700700 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
701 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800702 {
703 this->setOrigin(bounds.x(), bounds.y());
704 }
reedd9544982014-09-09 18:46:22 -0700705
706private:
piotaixrb5fae932014-09-24 13:03:30 -0700707
reedd9544982014-09-09 18:46:22 -0700708 typedef SkBitmapDevice INHERITED;
709};
710
reed96a857e2015-01-25 10:33:58 -0800711SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000712 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800713 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800714 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000715{
716 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700717
halcanary385fe4d2015-08-26 13:07:48 -0700718 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
719 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700720}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000721
reed78e27682014-11-19 08:04:34 -0800722SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700723 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700724 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800725 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700726{
727 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700728
halcanary385fe4d2015-08-26 13:07:48 -0700729 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700730}
731
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000732SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000733 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700734 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800735 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000736{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000737 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700738
reedd9544982014-09-09 18:46:22 -0700739 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740}
741
robertphillipsfcf78292015-06-19 11:49:52 -0700742SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
743 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700744 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800745 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700746{
747 inc_canvas();
748
749 this->init(device, flags);
750}
751
reed4a8126e2014-09-22 07:29:03 -0700752SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700753 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700754 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800755 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700756{
757 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700758
halcanary385fe4d2015-08-26 13:07:48 -0700759 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700760 this->init(device, kDefault_InitFlags);
761}
reed29c857d2014-09-21 10:25:07 -0700762
reed4a8126e2014-09-22 07:29:03 -0700763SkCanvas::SkCanvas(const SkBitmap& bitmap)
764 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
765 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800766 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700767{
768 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700769
halcanary385fe4d2015-08-26 13:07:48 -0700770 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700771 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772}
773
774SkCanvas::~SkCanvas() {
775 // free up the contents of our deque
776 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000777
reed@android.com8a1c16f2008-12-17 15:59:43 +0000778 this->internalRestore(); // restore the last, since we're going away
779
halcanary385fe4d2015-08-26 13:07:48 -0700780 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000781
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782 dec_canvas();
783}
784
fmalita77650002016-01-21 18:47:11 -0800785#ifdef SK_SUPPORT_LEGACY_DRAWFLTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786SkDrawFilter* SkCanvas::getDrawFilter() const {
787 return fMCRec->fFilter;
788}
789
790SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700791 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
793 return filter;
794}
fmalita77650002016-01-21 18:47:11 -0800795#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000797SkMetaData& SkCanvas::getMetaData() {
798 // metadata users are rare, so we lazily allocate it. If that changes we
799 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700800 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000801 fMetaData = new SkMetaData;
802 }
803 return *fMetaData;
804}
805
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806///////////////////////////////////////////////////////////////////////////////
807
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000808void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000809 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000810 if (device) {
811 device->flush();
812 }
813}
814
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000815SkISize SkCanvas::getTopLayerSize() const {
816 SkBaseDevice* d = this->getTopDevice();
817 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
818}
819
820SkIPoint SkCanvas::getTopLayerOrigin() const {
821 SkBaseDevice* d = this->getTopDevice();
822 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
823}
824
825SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000826 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000827 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
828}
829
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000830SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000832 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833 SkASSERT(rec && rec->fLayer);
834 return rec->fLayer->fDevice;
835}
836
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000837SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000838 if (updateMatrixClip) {
839 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
840 }
reed@google.com9266fed2011-03-30 00:18:03 +0000841 return fMCRec->fTopLayer->fDevice;
842}
843
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000844bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
845 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
846 return false;
847 }
848
849 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700850 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700851 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000852 return false;
853 }
854 weAllocated = true;
855 }
856
reedcf01e312015-05-23 19:14:51 -0700857 SkAutoPixmapUnlock unlocker;
858 if (bitmap->requestLock(&unlocker)) {
859 const SkPixmap& pm = unlocker.pixmap();
860 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
861 return true;
862 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000863 }
864
865 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700866 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000867 }
868 return false;
869}
reed@google.com51df9e32010-12-23 19:29:18 +0000870
bsalomon@google.comc6980972011-11-02 19:57:21 +0000871bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000872 SkIRect r = srcRect;
873 const SkISize size = this->getBaseLayerSize();
874 if (!r.intersect(0, 0, size.width(), size.height())) {
875 bitmap->reset();
876 return false;
877 }
878
reed84825042014-09-02 12:50:45 -0700879 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000880 // bitmap will already be reset.
881 return false;
882 }
883 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
884 bitmap->reset();
885 return false;
886 }
887 return true;
888}
889
reed96472de2014-12-10 09:53:42 -0800890bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000891 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000892 if (!device) {
893 return false;
894 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000895 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800896
reed96472de2014-12-10 09:53:42 -0800897 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
898 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000899 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000900 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000901
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000902 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800903 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000904}
905
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000906bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
907 if (bitmap.getTexture()) {
908 return false;
909 }
reedcf01e312015-05-23 19:14:51 -0700910
911 SkAutoPixmapUnlock unlocker;
912 if (bitmap.requestLock(&unlocker)) {
913 const SkPixmap& pm = unlocker.pixmap();
914 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000915 }
916 return false;
917}
918
919bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
920 int x, int y) {
921 switch (origInfo.colorType()) {
922 case kUnknown_SkColorType:
923 case kIndex_8_SkColorType:
924 return false;
925 default:
926 break;
927 }
halcanary96fcdcc2015-08-27 07:41:13 -0700928 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000929 return false;
930 }
931
932 const SkISize size = this->getBaseLayerSize();
933 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
934 if (!target.intersect(0, 0, size.width(), size.height())) {
935 return false;
936 }
937
938 SkBaseDevice* device = this->getDevice();
939 if (!device) {
940 return false;
941 }
942
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000943 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700944 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000945
946 // if x or y are negative, then we have to adjust pixels
947 if (x > 0) {
948 x = 0;
949 }
950 if (y > 0) {
951 y = 0;
952 }
953 // here x,y are either 0 or negative
954 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
955
reed4af35f32014-06-27 17:47:49 -0700956 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700957 const bool completeOverwrite = info.dimensions() == size;
958 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700959
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000960 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000961 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000962}
reed@google.com51df9e32010-12-23 19:29:18 +0000963
junov@google.com4370aed2012-01-18 16:21:08 +0000964SkCanvas* SkCanvas::canvasForDrawIter() {
965 return this;
966}
967
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968//////////////////////////////////////////////////////////////////////////////
969
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970void SkCanvas::updateDeviceCMCache() {
971 if (fDeviceCMDirty) {
972 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700973 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000975
halcanary96fcdcc2015-08-27 07:41:13 -0700976 if (nullptr == layer->fNext) { // only one layer
977 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000979 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980 do {
reed687fa1c2015-04-07 08:00:56 -0700981 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700982 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000983 }
984 fDeviceCMDirty = false;
985 }
986}
987
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988///////////////////////////////////////////////////////////////////////////////
989
reed2ff1fce2014-12-11 07:07:37 -0800990void SkCanvas::checkForDeferredSave() {
991 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800992 this->doSave();
993 }
994}
995
reedf0090cb2014-11-26 08:55:51 -0800996int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800997#ifdef SK_DEBUG
998 int count = 0;
999 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1000 for (;;) {
1001 const MCRec* rec = (const MCRec*)iter.next();
1002 if (!rec) {
1003 break;
1004 }
1005 count += 1 + rec->fDeferredSaveCount;
1006 }
1007 SkASSERT(count == fSaveCount);
1008#endif
1009 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001010}
1011
1012int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001013 fSaveCount += 1;
1014 fMCRec->fDeferredSaveCount += 1;
1015 return this->getSaveCount() - 1; // return our prev value
1016}
1017
1018void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001019 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001020
1021 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1022 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001023 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001024}
1025
1026void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001027 if (fMCRec->fDeferredSaveCount > 0) {
1028 SkASSERT(fSaveCount > 1);
1029 fSaveCount -= 1;
1030 fMCRec->fDeferredSaveCount -= 1;
1031 } else {
1032 // check for underflow
1033 if (fMCStack.count() > 1) {
1034 this->willRestore();
1035 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001036 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001037 this->internalRestore();
1038 this->didRestore();
1039 }
reedf0090cb2014-11-26 08:55:51 -08001040 }
1041}
1042
1043void SkCanvas::restoreToCount(int count) {
1044 // sanity check
1045 if (count < 1) {
1046 count = 1;
1047 }
mtkleinf0f14112014-12-12 08:46:25 -08001048
reedf0090cb2014-11-26 08:55:51 -08001049 int n = this->getSaveCount() - count;
1050 for (int i = 0; i < n; ++i) {
1051 this->restore();
1052 }
1053}
1054
reed2ff1fce2014-12-11 07:07:37 -08001055void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001057 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001059
reed687fa1c2015-04-07 08:00:56 -07001060 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001061}
1062
reed4960eee2015-12-18 07:09:18 -08001063bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001064#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001065 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@google.comb93ba452014-03-10 19:47:58 +00001066#else
1067 return true;
1068#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069}
1070
reed4960eee2015-12-18 07:09:18 -08001071bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001072 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001073 SkIRect clipBounds;
1074 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001075 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001076 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001077
reed96e657d2015-03-10 17:30:07 -07001078 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1079
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001080 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -07001081 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblancodb64af32015-12-09 10:11:43 -08001082 if (bounds && !imageFilter->canComputeFastBounds()) {
1083 bounds = nullptr;
1084 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001085 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001086 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001087 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001089
reed96e657d2015-03-10 17:30:07 -07001090 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001091 r.roundOut(&ir);
1092 // early exit if the layer's bounds are clipped out
1093 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001094 if (BoundsAffectsClip(saveLayerFlags)) {
reed9b3aa542015-03-11 08:47:12 -07001095 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001096 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001097 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001098 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099 }
1100 } else { // no user bounds, so just use the clip
1101 ir = clipBounds;
1102 }
reed180aec42015-03-11 10:39:04 -07001103 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001104
reed4960eee2015-12-18 07:09:18 -08001105 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001106 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -07001107 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -07001108 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001109 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001110 }
1111
1112 if (intersection) {
1113 *intersection = ir;
1114 }
1115 return true;
1116}
1117
reedbada1882015-12-21 13:09:44 -08001118#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS
reed4960eee2015-12-18 07:09:18 -08001119uint32_t SkCanvas::SaveFlagsToSaveLayerFlags(SaveFlags flags) {
1120 uint32_t layerFlags = 0;
1121
1122 if (0 == (flags & kClipToLayer_SaveFlag)) {
1123 layerFlags |= kDontClipToLayer_PrivateSaveLayerFlag;
reedd990e2f2014-12-22 11:58:30 -08001124 }
reed4960eee2015-12-18 07:09:18 -08001125 if (0 == (flags & kHasAlphaLayer_SaveFlag)) {
1126 layerFlags |= kIsOpaque_SaveLayerFlag;
1127 }
1128 return layerFlags;
1129}
scroggoffe031e2016-01-04 07:16:32 -08001130
1131uint32_t SkCanvas::SaveLayerFlagsToSaveFlags(SaveLayerFlags layerFlags) {
1132 uint32_t saveFlags = 0;
1133
1134 if (0 == (layerFlags & kDontClipToLayer_PrivateSaveLayerFlag)) {
1135 saveFlags |= kClipToLayer_SaveFlag;
1136 }
1137 if (0 == (layerFlags & kIsOpaque_SaveLayerFlag)) {
1138 saveFlags |= kHasAlphaLayer_SaveFlag;
1139 }
1140 return saveFlags;
1141}
reedbada1882015-12-21 13:09:44 -08001142#endif
reed4960eee2015-12-18 07:09:18 -08001143
reed4960eee2015-12-18 07:09:18 -08001144int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1145 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001146}
1147
reedbada1882015-12-21 13:09:44 -08001148#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS
reed2ff1fce2014-12-11 07:07:37 -08001149int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reed4960eee2015-12-18 07:09:18 -08001150 return this->saveLayer(SaveLayerRec(bounds, paint, SaveFlagsToSaveLayerFlags(flags)));
reed@google.com8926b162012-03-23 15:36:36 +00001151}
reedbada1882015-12-21 13:09:44 -08001152#endif
reed@google.com8926b162012-03-23 15:36:36 +00001153
reed70ee31b2015-12-10 13:44:45 -08001154int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001155 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1156}
1157
1158int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1159 SaveLayerRec rec(origRec);
1160 if (gIgnoreSaveLayerBounds) {
1161 rec.fBounds = nullptr;
1162 }
1163 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1164 fSaveCount += 1;
1165 this->internalSaveLayer(rec, strategy);
1166 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001167}
1168
reedbfd5f172016-01-07 11:28:08 -08001169static void draw_filter_into_device(SkBaseDevice* src, const SkImageFilter* filter,
1170 SkBaseDevice* dst, const SkMatrix& ctm) {
robertphillips7354a4b2015-12-16 05:08:27 -08001171
1172 SkBitmap srcBM;
1173
1174#if SK_SUPPORT_GPU
1175 GrRenderTarget* srcRT = src->accessRenderTarget();
1176 if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) {
1177 // When both the src & the dst are on the gpu but the src doesn't have a texture,
1178 // we create a temporary texture for the draw.
1179 // TODO: we should actually only copy the portion of the source needed to apply the image
1180 // filter
1181 GrContext* context = srcRT->getContext();
1182 SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(srcRT->desc(), true));
1183
1184 context->copySurface(tex, srcRT);
1185
1186 GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM);
1187 } else
1188#endif
1189 {
1190 srcBM = src->accessBitmap(false);
1191 }
1192
1193 SkCanvas c(dst);
1194
reedbfd5f172016-01-07 11:28:08 -08001195 SkAutoTUnref<SkImageFilter> localF(filter->newWithLocalMatrix(ctm));
robertphillips7354a4b2015-12-16 05:08:27 -08001196 SkPaint p;
reedbfd5f172016-01-07 11:28:08 -08001197 p.setImageFilter(localF);
1198 const SkScalar x = SkIntToScalar(src->getOrigin().x());
1199 const SkScalar y = SkIntToScalar(src->getOrigin().y());
1200 c.drawBitmap(srcBM, x, y, &p);
robertphillips7354a4b2015-12-16 05:08:27 -08001201}
reed70ee31b2015-12-10 13:44:45 -08001202
reed4960eee2015-12-18 07:09:18 -08001203void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1204 const SkRect* bounds = rec.fBounds;
1205 const SkPaint* paint = rec.fPaint;
1206 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1207
reed@google.comb93ba452014-03-10 19:47:58 +00001208#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001209 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001210#endif
1211
junov@chromium.orga907ac32012-02-24 21:54:07 +00001212 // do this before we create the layer. We don't call the public save() since
1213 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001214 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001215
1216 fDeviceCMDirty = true;
1217
1218 SkIRect ir;
reed4960eee2015-12-18 07:09:18 -08001219 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001220 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221 }
1222
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001223 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1224 // the clipRectBounds() call above?
1225 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001226 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001227 }
1228
reed4960eee2015-12-18 07:09:18 -08001229 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001230 SkPixelGeometry geo = fProps.pixelGeometry();
1231 if (paint) {
reed76033be2015-03-14 10:54:31 -07001232 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001233 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001234 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001235 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001236 }
1237 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001238 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1239 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240
reedb2db8982014-11-13 12:41:02 -08001241 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001242 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001243 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001244 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001245 }
reedb2db8982014-11-13 12:41:02 -08001246
reed61f501f2015-04-29 08:34:00 -07001247 bool forceSpriteOnRestore = false;
1248 {
reed70ee31b2015-12-10 13:44:45 -08001249 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001250 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001251 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001252 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1253 preserveLCDText, false);
reed61f501f2015-04-29 08:34:00 -07001254 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001255 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001256 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001257 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1258 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001259 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001260 SkErrorInternals::SetError(kInternalError_SkError,
1261 "Unable to create device for layer.");
1262 return;
1263 }
1264 forceSpriteOnRestore = true;
1265 }
1266 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001267 }
reed@google.com6f8f2922011-03-04 22:27:10 +00001268 device->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001269
reedbfd5f172016-01-07 11:28:08 -08001270 if (rec.fBackdrop) {
1271 draw_filter_into_device(fMCRec->fTopLayer->fDevice, rec.fBackdrop, device, fMCRec->fMatrix);
robertphillips7354a4b2015-12-16 05:08:27 -08001272 }
1273
halcanary385fe4d2015-08-26 13:07:48 -07001274 DeviceCM* layer =
1275 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276 device->unref();
1277
1278 layer->fNext = fMCRec->fTopLayer;
1279 fMCRec->fLayer = layer;
1280 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281}
1282
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001283int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001284 if (0xFF == alpha) {
1285 return this->saveLayer(bounds, nullptr);
1286 } else {
1287 SkPaint tmpPaint;
1288 tmpPaint.setAlpha(alpha);
1289 return this->saveLayer(bounds, &tmpPaint);
1290 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001291}
1292
reedbada1882015-12-21 13:09:44 -08001293#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1295 SaveFlags flags) {
1296 if (0xFF == alpha) {
halcanary96fcdcc2015-08-27 07:41:13 -07001297 return this->saveLayer(bounds, nullptr, flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298 } else {
1299 SkPaint tmpPaint;
1300 tmpPaint.setAlpha(alpha);
1301 return this->saveLayer(bounds, &tmpPaint, flags);
1302 }
1303}
reedbada1882015-12-21 13:09:44 -08001304#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306void SkCanvas::internalRestore() {
1307 SkASSERT(fMCStack.count() != 0);
1308
1309 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001310 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311
reed687fa1c2015-04-07 08:00:56 -07001312 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001313
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001314 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315 DeviceCM* layer = fMCRec->fLayer; // may be null
1316 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001317 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318
1319 // now do the normal restore()
1320 fMCRec->~MCRec(); // balanced in save()
1321 fMCStack.pop_back();
1322 fMCRec = (MCRec*)fMCStack.back();
1323
1324 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1325 since if we're being recorded, we don't want to record this (the
1326 recorder will have already recorded the restore).
1327 */
bsalomon49f085d2014-09-05 13:34:00 -07001328 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001329 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001330 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001331 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001332 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001333 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001335 delete layer;
reedb679ca82015-04-07 04:40:48 -07001336 } else {
1337 // we're at the root
reeda499f902015-05-01 09:34:31 -07001338 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001339 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001341 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342}
1343
reed4a8126e2014-09-22 07:29:03 -07001344SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001345 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001346 props = &fProps;
1347 }
1348 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001349}
1350
reed4a8126e2014-09-22 07:29:03 -07001351SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001352 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001353 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001354}
1355
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001356SkImageInfo SkCanvas::imageInfo() const {
1357 SkBaseDevice* dev = this->getDevice();
1358 if (dev) {
1359 return dev->imageInfo();
1360 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001361 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001362 }
1363}
1364
1365const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001366 SkPixmap pmap;
1367 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001368 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001369 }
1370 if (info) {
1371 *info = pmap.info();
1372 }
1373 if (rowBytes) {
1374 *rowBytes = pmap.rowBytes();
1375 }
1376 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001377}
1378
reed884e97c2015-05-26 11:31:54 -07001379bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001380 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001381 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001382}
1383
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001384void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001385 SkPixmap pmap;
1386 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001387 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001388 }
1389 if (info) {
1390 *info = pmap.info();
1391 }
1392 if (rowBytes) {
1393 *rowBytes = pmap.rowBytes();
1394 }
1395 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001396 *origin = this->getTopDevice(false)->getOrigin();
1397 }
reed884e97c2015-05-26 11:31:54 -07001398 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001399}
1400
reed884e97c2015-05-26 11:31:54 -07001401bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001402 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001403 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001404}
1405
reed@android.com8a1c16f2008-12-17 15:59:43 +00001406/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001408void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001409 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001410 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001411 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412 paint = &tmp;
1413 }
reed@google.com4b226022011-01-11 18:32:13 +00001414
reed@google.com8926b162012-03-23 15:36:36 +00001415 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001417 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001418 paint = &looper.paint();
1419 SkImageFilter* filter = paint->getImageFilter();
1420 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001421 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001422 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001423 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001424 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001425 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001426 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001427 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblancodb64af32015-12-09 10:11:43 -08001428 SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
senorblancobe129b22014-08-08 07:14:35 -07001429 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reed4e23cda2016-01-11 10:56:59 -08001430 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001431 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001432 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001433 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001434 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1435 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001436 }
reed61f501f2015-04-29 08:34:00 -07001437 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001438 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001439 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001440 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001441 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001442 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001443 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001444 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001445}
1446
reed32704672015-12-16 08:27:10 -08001447/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001448
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001449void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001450 SkMatrix m;
1451 m.setTranslate(dx, dy);
1452 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001453}
1454
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001455void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001456 SkMatrix m;
1457 m.setScale(sx, sy);
1458 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001459}
1460
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001461void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001462 SkMatrix m;
1463 m.setRotate(degrees);
1464 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001465}
1466
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001467void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001468 SkMatrix m;
1469 m.setSkew(sx, sy);
1470 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001471}
1472
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001473void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001474 if (matrix.isIdentity()) {
1475 return;
1476 }
1477
reed2ff1fce2014-12-11 07:07:37 -08001478 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001479 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001480 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001481 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001482
1483 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001484}
1485
reed86a17e72015-05-14 12:25:22 -07001486void SkCanvas::setMatrix(const SkMatrix& matrix) {
1487 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001489 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001490 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001491 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001492}
1493
reed@android.com8a1c16f2008-12-17 15:59:43 +00001494void SkCanvas::resetMatrix() {
1495 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001496
reed@android.com8a1c16f2008-12-17 15:59:43 +00001497 matrix.reset();
1498 this->setMatrix(matrix);
1499}
1500
1501//////////////////////////////////////////////////////////////////////////////
1502
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001503void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001504 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001505 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1506 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001507}
1508
1509void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001510#ifdef SK_ENABLE_CLIP_QUICKREJECT
1511 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001512 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001513 return false;
1514 }
1515
reed@google.com3b3e8952012-08-16 20:53:31 +00001516 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001517 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001518 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001519
reed687fa1c2015-04-07 08:00:56 -07001520 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001521 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001522 }
1523 }
1524#endif
1525
bsalomonac8cabd2015-11-20 18:53:07 -08001526 if (!fAllowSoftClip) {
1527 edgeStyle = kHard_ClipEdgeStyle;
1528 }
reed90ba0952015-11-20 13:42:47 -08001529
reedc64eff52015-11-21 12:39:45 -08001530 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1531 SkRect devR;
1532 if (rectStaysRect) {
1533 fMCRec->fMatrix.mapRect(&devR, rect);
1534 }
bsalomonac8cabd2015-11-20 18:53:07 -08001535
reedc64eff52015-11-21 12:39:45 -08001536 // Check if we can quick-accept the clip call (and do nothing)
1537 //
1538 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1539 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1540 // might allow lazy save/restores to eliminate entire save/restore blocks.
1541 //
1542 if (SkRegion::kIntersect_Op == op &&
1543 kHard_ClipEdgeStyle == edgeStyle
1544 && rectStaysRect)
1545 {
1546 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1547#if 0
1548 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1549 rect.left(), rect.top(), rect.right(), rect.bottom());
1550#endif
1551 return;
1552 }
1553 }
1554
1555 AutoValidateClip avc(this);
1556
1557 fDeviceCMDirty = true;
1558 fCachedLocalClipBoundsDirty = true;
1559
1560 if (rectStaysRect) {
1561 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1562 fClipStack->clipDevRect(devR, op, isAA);
1563 fMCRec->fRasterClip.op(devR, this->getBaseLayerSize(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001564 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001565 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001566 // and clip against that, since it can handle any matrix. However, to
1567 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1568 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001569 SkPath path;
1570
1571 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001572 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001573 }
1574}
1575
reed73e714e2014-09-04 09:02:23 -07001576static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1577 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001578 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001579}
1580
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001581void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001582 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001583 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001584 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001585 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1586 } else {
1587 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001588 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001589}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001590
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001591void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001592 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001593 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001594 AutoValidateClip avc(this);
1595
1596 fDeviceCMDirty = true;
1597 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001598 if (!fAllowSoftClip) {
1599 edgeStyle = kHard_ClipEdgeStyle;
1600 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001601
reed687fa1c2015-04-07 08:00:56 -07001602 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001603
robertphillips125f19a2015-11-23 09:00:05 -08001604 fMCRec->fRasterClip.op(transformedRRect, this->getBaseLayerSize(), op,
1605 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001606 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001607 }
1608
1609 SkPath path;
1610 path.addRRect(rrect);
1611 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001612 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001613}
1614
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001615void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001616 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001617 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001618
1619 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1620 SkRect r;
1621 if (path.isRect(&r)) {
1622 this->onClipRect(r, op, edgeStyle);
1623 return;
1624 }
1625 SkRRect rrect;
1626 if (path.isOval(&r)) {
1627 rrect.setOval(r);
1628 this->onClipRRect(rrect, op, edgeStyle);
1629 return;
1630 }
1631 if (path.isRRect(&rrect)) {
1632 this->onClipRRect(rrect, op, edgeStyle);
1633 return;
1634 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001635 }
robertphillips39f05382015-11-24 09:30:12 -08001636
1637 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001638}
1639
1640void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001641#ifdef SK_ENABLE_CLIP_QUICKREJECT
1642 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001643 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001644 return false;
1645 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001646
reed@google.com3b3e8952012-08-16 20:53:31 +00001647 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001648 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001649 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001650
reed687fa1c2015-04-07 08:00:56 -07001651 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001652 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001653 }
1654 }
1655#endif
1656
reed@google.com5c3d1472011-02-22 19:12:23 +00001657 AutoValidateClip avc(this);
1658
reed@android.com8a1c16f2008-12-17 15:59:43 +00001659 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001660 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001661 if (!fAllowSoftClip) {
1662 edgeStyle = kHard_ClipEdgeStyle;
1663 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664
1665 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001666 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001667
reed@google.comfe701122011-11-08 19:41:23 +00001668 // Check if the transfomation, or the original path itself
1669 // made us empty. Note this can also happen if we contained NaN
1670 // values. computing the bounds detects this, and will set our
1671 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1672 if (devPath.getBounds().isEmpty()) {
1673 // resetting the path will remove any NaN or other wanky values
1674 // that might upset our scan converter.
1675 devPath.reset();
1676 }
1677
reed@google.com5c3d1472011-02-22 19:12:23 +00001678 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001679 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001680
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001681 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001682 bool clipIsAA = getClipStack()->asPath(&devPath);
1683 if (clipIsAA) {
1684 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001685 }
fmalita1a481fe2015-02-04 07:39:34 -08001686
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001687 op = SkRegion::kReplace_Op;
1688 }
1689
reed73e714e2014-09-04 09:02:23 -07001690 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001691}
1692
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001693void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001694 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001695 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001696}
1697
1698void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001699 AutoValidateClip avc(this);
1700
reed@android.com8a1c16f2008-12-17 15:59:43 +00001701 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001702 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001703
reed@google.com5c3d1472011-02-22 19:12:23 +00001704 // todo: signal fClipStack that we have a region, and therefore (I guess)
1705 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001706 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001707
reed1f836ee2014-07-07 07:49:34 -07001708 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001709}
1710
reed@google.com819c9212011-02-23 18:56:55 +00001711#ifdef SK_DEBUG
1712void SkCanvas::validateClip() const {
1713 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001714 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001715 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001716 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001717 return;
1718 }
1719
reed@google.com819c9212011-02-23 18:56:55 +00001720 SkIRect ir;
1721 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001722 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001723
reed687fa1c2015-04-07 08:00:56 -07001724 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001725 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001726 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001727 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001728 case SkClipStack::Element::kRect_Type:
1729 element->getRect().round(&ir);
1730 tmpClip.op(ir, element->getOp());
1731 break;
1732 case SkClipStack::Element::kEmpty_Type:
1733 tmpClip.setEmpty();
1734 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001735 default: {
1736 SkPath path;
1737 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001738 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001739 break;
1740 }
reed@google.com819c9212011-02-23 18:56:55 +00001741 }
1742 }
reed@google.com819c9212011-02-23 18:56:55 +00001743}
1744#endif
1745
reed@google.com90c07ea2012-04-13 13:50:27 +00001746void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001747 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001748 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001749
halcanary96fcdcc2015-08-27 07:41:13 -07001750 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001751 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001752 }
1753}
1754
reed@google.com5c3d1472011-02-22 19:12:23 +00001755///////////////////////////////////////////////////////////////////////////////
1756
reed@google.com754de5f2014-02-24 19:38:20 +00001757bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001758 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001759}
1760
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001761bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001762 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001763}
1764
reed@google.com3b3e8952012-08-16 20:53:31 +00001765bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001766 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001767 return true;
1768
reed1f836ee2014-07-07 07:49:34 -07001769 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001770 return true;
1771 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001772
reed1f836ee2014-07-07 07:49:34 -07001773 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001774 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001775 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001776 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001777 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001778 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001779
reed@android.coma380ae42009-07-21 01:17:02 +00001780 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001781 // TODO: should we use | instead, or compare all 4 at once?
1782 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001783 return true;
1784 }
reed@google.comc0784db2013-12-13 21:16:12 +00001785 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001786 return true;
1787 }
1788 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001789 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001790}
1791
reed@google.com3b3e8952012-08-16 20:53:31 +00001792bool SkCanvas::quickReject(const SkPath& path) const {
1793 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001794}
1795
reed@google.com3b3e8952012-08-16 20:53:31 +00001796bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001797 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001798 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001799 return false;
1800 }
1801
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001802 SkMatrix inverse;
1803 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001804 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001805 if (bounds) {
1806 bounds->setEmpty();
1807 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001808 return false;
1809 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001810
bsalomon49f085d2014-09-05 13:34:00 -07001811 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001812 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001813 // adjust it outwards in case we are antialiasing
1814 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001815
reed@google.com8f4d2302013-12-17 16:44:46 +00001816 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1817 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001818 inverse.mapRect(bounds, r);
1819 }
1820 return true;
1821}
1822
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001823bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001824 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001825 if (clip.isEmpty()) {
1826 if (bounds) {
1827 bounds->setEmpty();
1828 }
1829 return false;
1830 }
1831
bsalomon49f085d2014-09-05 13:34:00 -07001832 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001833 *bounds = clip.getBounds();
1834 }
1835 return true;
1836}
1837
reed@android.com8a1c16f2008-12-17 15:59:43 +00001838const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001839 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001840}
1841
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001842const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001843 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001844}
1845
reed@google.com9c135db2014-03-12 18:28:35 +00001846GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1847 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001848 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001849}
1850
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001851GrContext* SkCanvas::getGrContext() {
1852#if SK_SUPPORT_GPU
1853 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001854 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001855 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001856 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001857 return renderTarget->getContext();
1858 }
1859 }
1860#endif
1861
halcanary96fcdcc2015-08-27 07:41:13 -07001862 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001863
1864}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001865
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001866void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1867 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001868 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001869 if (outer.isEmpty()) {
1870 return;
1871 }
1872 if (inner.isEmpty()) {
1873 this->drawRRect(outer, paint);
1874 return;
1875 }
1876
1877 // We don't have this method (yet), but technically this is what we should
1878 // be able to assert...
1879 // SkASSERT(outer.contains(inner));
1880 //
1881 // For now at least check for containment of bounds
1882 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1883
1884 this->onDrawDRRect(outer, inner, paint);
1885}
1886
reed41af9662015-01-05 07:49:08 -08001887// These need to stop being virtual -- clients need to override the onDraw... versions
1888
1889void SkCanvas::drawPaint(const SkPaint& paint) {
1890 this->onDrawPaint(paint);
1891}
1892
1893void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1894 this->onDrawRect(r, paint);
1895}
1896
1897void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1898 this->onDrawOval(r, paint);
1899}
1900
1901void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1902 this->onDrawRRect(rrect, paint);
1903}
1904
1905void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1906 this->onDrawPoints(mode, count, pts, paint);
1907}
1908
1909void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1910 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1911 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1912 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1913 indices, indexCount, paint);
1914}
1915
1916void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1917 this->onDrawPath(path, paint);
1918}
1919
reeda85d4d02015-05-06 12:56:48 -07001920void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001921 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001922 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001923}
1924
reede47829b2015-08-06 10:02:53 -07001925void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1926 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001927 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001928 if (dst.isEmpty() || src.isEmpty()) {
1929 return;
1930 }
1931 this->onDrawImageRect(image, &src, dst, paint, constraint);
1932}
reed41af9662015-01-05 07:49:08 -08001933
reed84984ef2015-07-17 07:09:43 -07001934void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1935 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001936 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001937 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001938}
1939
reede47829b2015-08-06 10:02:53 -07001940void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1941 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001942 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001943 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1944 constraint);
1945}
reede47829b2015-08-06 10:02:53 -07001946
reed4c21dc52015-06-25 12:32:03 -07001947void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1948 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001949 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001950 if (dst.isEmpty()) {
1951 return;
1952 }
1953 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001954 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001955 }
1956 this->onDrawImageNine(image, center, dst, paint);
1957}
1958
reed41af9662015-01-05 07:49:08 -08001959void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001960 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001961 return;
1962 }
reed41af9662015-01-05 07:49:08 -08001963 this->onDrawBitmap(bitmap, dx, dy, paint);
1964}
1965
reede47829b2015-08-06 10:02:53 -07001966void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001967 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001968 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001969 return;
1970 }
reede47829b2015-08-06 10:02:53 -07001971 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001972}
1973
reed84984ef2015-07-17 07:09:43 -07001974void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1975 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001976 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001977}
1978
reede47829b2015-08-06 10:02:53 -07001979void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1980 SrcRectConstraint constraint) {
1981 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1982 constraint);
1983}
reede47829b2015-08-06 10:02:53 -07001984
reed41af9662015-01-05 07:49:08 -08001985void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1986 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001987 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001988 return;
1989 }
reed4c21dc52015-06-25 12:32:03 -07001990 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001991 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001992 }
reed41af9662015-01-05 07:49:08 -08001993 this->onDrawBitmapNine(bitmap, center, dst, paint);
1994}
1995
reed71c3c762015-06-24 10:29:17 -07001996void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1997 const SkColor colors[], int count, SkXfermode::Mode mode,
1998 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001999 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002000 if (count <= 0) {
2001 return;
2002 }
2003 SkASSERT(atlas);
2004 SkASSERT(xform);
2005 SkASSERT(tex);
2006 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2007}
2008
reede47829b2015-08-06 10:02:53 -07002009void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2010 const SkPaint* paint, SrcRectConstraint constraint) {
2011 if (src) {
2012 this->drawImageRect(image, *src, dst, paint, constraint);
2013 } else {
2014 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2015 dst, paint, constraint);
2016 }
2017}
2018void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2019 const SkPaint* paint, SrcRectConstraint constraint) {
2020 if (src) {
2021 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2022 } else {
2023 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2024 dst, paint, constraint);
2025 }
2026}
2027
reed@android.com8a1c16f2008-12-17 15:59:43 +00002028//////////////////////////////////////////////////////////////////////////////
2029// These are the virtual drawing methods
2030//////////////////////////////////////////////////////////////////////////////
2031
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002032void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002033 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002034 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2035 }
2036}
2037
reed41af9662015-01-05 07:49:08 -08002038void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002039 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002040 this->internalDrawPaint(paint);
2041}
2042
2043void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002044 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002045
2046 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002047 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002048 }
2049
reed@google.com4e2b3d32011-04-07 14:18:59 +00002050 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002051}
2052
reed41af9662015-01-05 07:49:08 -08002053void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2054 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002055 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002056 if ((long)count <= 0) {
2057 return;
2058 }
2059
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002060 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002061 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002062 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002063 // special-case 2 points (common for drawing a single line)
2064 if (2 == count) {
2065 r.set(pts[0], pts[1]);
2066 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002067 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002068 }
senorblanco87e066e2015-10-28 11:23:36 -07002069 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2070 return;
2071 }
2072 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002073 }
reed@google.coma584aed2012-05-16 14:06:02 +00002074
halcanary96fcdcc2015-08-27 07:41:13 -07002075 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002076
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002077 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002078
reed@android.com8a1c16f2008-12-17 15:59:43 +00002079 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002080 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002081 }
reed@google.com4b226022011-01-11 18:32:13 +00002082
reed@google.com4e2b3d32011-04-07 14:18:59 +00002083 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002084}
2085
reed41af9662015-01-05 07:49:08 -08002086void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002087 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002088 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002089 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002090 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002091 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2092 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2093 SkRect tmp(r);
2094 tmp.sort();
2095
senorblanco87e066e2015-10-28 11:23:36 -07002096 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2097 return;
2098 }
2099 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002100 }
reed@google.com4b226022011-01-11 18:32:13 +00002101
reedc83a2972015-07-16 07:40:45 -07002102 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002103
2104 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002105 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002106 }
2107
reed@google.com4e2b3d32011-04-07 14:18:59 +00002108 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002109}
2110
reed41af9662015-01-05 07:49:08 -08002111void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002112 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002113 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002114 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002115 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002116 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2117 return;
2118 }
2119 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002120 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002121
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002122 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002123
2124 while (iter.next()) {
2125 iter.fDevice->drawOval(iter, oval, looper.paint());
2126 }
2127
2128 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002129}
2130
reed41af9662015-01-05 07:49:08 -08002131void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002132 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002133 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002134 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002135 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002136 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2137 return;
2138 }
2139 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002140 }
2141
2142 if (rrect.isRect()) {
2143 // call the non-virtual version
2144 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002145 return;
2146 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002147 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002148 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2149 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002150 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002151
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002152 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002153
2154 while (iter.next()) {
2155 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2156 }
2157
2158 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002159}
2160
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002161void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2162 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002163 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002164 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002165 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002166 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2167 return;
2168 }
2169 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002170 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002171
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002172 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002173
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002174 while (iter.next()) {
2175 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2176 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002177
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002178 LOOPER_END
2179}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002180
reed41af9662015-01-05 07:49:08 -08002181void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002182 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002183 if (!path.isFinite()) {
2184 return;
2185 }
2186
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002187 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002188 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002189 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002190 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002191 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2192 return;
2193 }
2194 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002195 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002196
2197 const SkRect& r = path.getBounds();
2198 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002199 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002200 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002201 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002202 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002203 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002204
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002205 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002206
2207 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002208 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002209 }
2210
reed@google.com4e2b3d32011-04-07 14:18:59 +00002211 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002212}
2213
reed262a71b2015-12-05 13:07:27 -08002214bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002215 if (!paint.getImageFilter()) {
2216 return false;
2217 }
2218
2219 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002220 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002221 return false;
2222 }
2223
2224 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2225 // Once we can filter and the filter will return a result larger than itself, we should be
2226 // able to remove this constraint.
2227 // skbug.com/4526
2228 //
2229 SkPoint pt;
2230 ctm.mapXY(x, y, &pt);
2231 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2232 return ir.contains(fMCRec->fRasterClip.getBounds());
2233}
2234
reeda85d4d02015-05-06 12:56:48 -07002235void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002236 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002237 SkRect bounds = SkRect::MakeXYWH(x, y,
2238 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002239 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002240 SkRect tmp = bounds;
2241 if (paint) {
2242 paint->computeFastBounds(tmp, &tmp);
2243 }
2244 if (this->quickReject(tmp)) {
2245 return;
2246 }
reeda85d4d02015-05-06 12:56:48 -07002247 }
2248
2249 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002250 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002251 paint = lazy.init();
2252 }
reed262a71b2015-12-05 13:07:27 -08002253
2254 const bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2255 *paint);
2256 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2257
reeda85d4d02015-05-06 12:56:48 -07002258 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002259 const SkPaint& pnt = looper.paint();
2260 if (drawAsSprite && pnt.getImageFilter()) {
2261 SkBitmap bitmap;
2262 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2263 SkPoint pt;
2264 iter.fMatrix->mapXY(x, y, &pt);
2265 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2266 SkScalarRoundToInt(pt.fX),
2267 SkScalarRoundToInt(pt.fY), pnt);
2268 }
2269 } else {
2270 iter.fDevice->drawImage(iter, image, x, y, pnt);
2271 }
reeda85d4d02015-05-06 12:56:48 -07002272 }
2273
2274 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002275}
2276
reed41af9662015-01-05 07:49:08 -08002277void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002278 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002279 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002280 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002281 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002282 if (paint) {
2283 paint->computeFastBounds(dst, &storage);
2284 }
2285 if (this->quickReject(storage)) {
2286 return;
2287 }
reeda85d4d02015-05-06 12:56:48 -07002288 }
2289 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002290 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002291 paint = lazy.init();
2292 }
2293
senorblancoc41e7e12015-12-07 12:51:30 -08002294 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002295 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002296
2297 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002298 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002299 }
2300
2301 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002302}
2303
reed41af9662015-01-05 07:49:08 -08002304void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002305 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002306 SkDEBUGCODE(bitmap.validate();)
2307
reed33366972015-10-08 09:22:02 -07002308 if (bitmap.drawsNothing()) {
2309 return;
2310 }
2311
2312 SkLazyPaint lazy;
2313 if (nullptr == paint) {
2314 paint = lazy.init();
2315 }
2316
2317 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2318
2319 SkRect storage;
2320 const SkRect* bounds = nullptr;
2321 if (paint->canComputeFastBounds()) {
2322 bitmap.getBounds(&storage);
2323 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002324 SkRect tmp = storage;
2325 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2326 return;
2327 }
2328 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002329 }
reed@google.com4b226022011-01-11 18:32:13 +00002330
reed262a71b2015-12-05 13:07:27 -08002331 const bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2332 bitmap.height(), *paint);
2333 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002334
2335 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002336 const SkPaint& pnt = looper.paint();
2337 if (drawAsSprite && pnt.getImageFilter()) {
2338 SkPoint pt;
2339 iter.fMatrix->mapXY(x, y, &pt);
2340 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2341 SkScalarRoundToInt(pt.fX),
2342 SkScalarRoundToInt(pt.fY), pnt);
2343 } else {
2344 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2345 }
reed33366972015-10-08 09:22:02 -07002346 }
reed262a71b2015-12-05 13:07:27 -08002347
reed33366972015-10-08 09:22:02 -07002348 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002349}
2350
reed@google.com9987ec32011-09-07 11:57:52 +00002351// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002352void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002353 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002354 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002355 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002356 return;
2357 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002358
halcanary96fcdcc2015-08-27 07:41:13 -07002359 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002360 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002361 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2362 return;
2363 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364 }
reed@google.com3d608122011-11-21 15:16:16 +00002365
reed@google.com33535f32012-09-25 15:37:50 +00002366 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002367 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002368 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002369 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002370
senorblancoc41e7e12015-12-07 12:51:30 -08002371 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002372 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002373
reed@google.com33535f32012-09-25 15:37:50 +00002374 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002375 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002376 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002377
reed@google.com33535f32012-09-25 15:37:50 +00002378 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002379}
2380
reed41af9662015-01-05 07:49:08 -08002381void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002382 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002383 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002384 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002385 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002386}
2387
reed4c21dc52015-06-25 12:32:03 -07002388void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2389 const SkPaint* paint) {
2390 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2391
halcanary96fcdcc2015-08-27 07:41:13 -07002392 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002393 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002394 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2395 return;
2396 }
reed@google.com3d608122011-11-21 15:16:16 +00002397 }
reed4c21dc52015-06-25 12:32:03 -07002398
2399 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002400 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002401 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002402 }
reed4c21dc52015-06-25 12:32:03 -07002403
senorblancoc41e7e12015-12-07 12:51:30 -08002404 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002405
2406 while (iter.next()) {
2407 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002408 }
reed4c21dc52015-06-25 12:32:03 -07002409
2410 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002411}
2412
reed41af9662015-01-05 07:49:08 -08002413void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2414 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002415 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002416 SkDEBUGCODE(bitmap.validate();)
2417
halcanary96fcdcc2015-08-27 07:41:13 -07002418 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002419 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002420 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2421 return;
2422 }
reed4c21dc52015-06-25 12:32:03 -07002423 }
2424
2425 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002426 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002427 paint = lazy.init();
2428 }
2429
senorblancoc41e7e12015-12-07 12:51:30 -08002430 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002431
2432 while (iter.next()) {
2433 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2434 }
2435
2436 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002437}
2438
reed@google.comf67e4cf2011-03-15 20:56:58 +00002439class SkDeviceFilteredPaint {
2440public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002441 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002442 uint32_t filteredFlags = device->filterTextFlags(paint);
2443 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002444 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002445 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002446 fPaint = newPaint;
2447 } else {
2448 fPaint = &paint;
2449 }
2450 }
2451
reed@google.comf67e4cf2011-03-15 20:56:58 +00002452 const SkPaint& paint() const { return *fPaint; }
2453
2454private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002455 const SkPaint* fPaint;
2456 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002457};
2458
bungeman@google.com52c748b2011-08-22 21:30:43 +00002459void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2460 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002461 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002462 draw.fDevice->drawRect(draw, r, paint);
2463 } else {
2464 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002465 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002466 draw.fDevice->drawRect(draw, r, p);
2467 }
2468}
2469
2470void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2471 const char text[], size_t byteLength,
2472 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002473 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002474
2475 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002476 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002477 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002478 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002479 return;
2480 }
2481
2482 SkScalar width = 0;
2483 SkPoint start;
2484
2485 start.set(0, 0); // to avoid warning
2486 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2487 SkPaint::kStrikeThruText_Flag)) {
2488 width = paint.measureText(text, byteLength);
2489
2490 SkScalar offsetX = 0;
2491 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2492 offsetX = SkScalarHalf(width);
2493 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2494 offsetX = width;
2495 }
2496 start.set(x - offsetX, y);
2497 }
2498
2499 if (0 == width) {
2500 return;
2501 }
2502
2503 uint32_t flags = paint.getFlags();
2504
2505 if (flags & (SkPaint::kUnderlineText_Flag |
2506 SkPaint::kStrikeThruText_Flag)) {
2507 SkScalar textSize = paint.getTextSize();
2508 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2509 SkRect r;
2510
2511 r.fLeft = start.fX;
2512 r.fRight = start.fX + width;
2513
2514 if (flags & SkPaint::kUnderlineText_Flag) {
2515 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2516 start.fY);
2517 r.fTop = offset;
2518 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002519 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002520 }
2521 if (flags & SkPaint::kStrikeThruText_Flag) {
2522 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2523 start.fY);
2524 r.fTop = offset;
2525 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002526 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002527 }
2528 }
2529}
2530
reed@google.come0d9ce82014-04-23 04:00:17 +00002531void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2532 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002533 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002534
2535 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002536 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002537 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002538 DrawTextDecorations(iter, dfp.paint(),
2539 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002540 }
2541
reed@google.com4e2b3d32011-04-07 14:18:59 +00002542 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543}
2544
reed@google.come0d9ce82014-04-23 04:00:17 +00002545void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2546 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002547 SkPoint textOffset = SkPoint::Make(0, 0);
2548
halcanary96fcdcc2015-08-27 07:41:13 -07002549 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002550
reed@android.com8a1c16f2008-12-17 15:59:43 +00002551 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002552 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002553 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002554 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002555 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002556
reed@google.com4e2b3d32011-04-07 14:18:59 +00002557 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002558}
2559
reed@google.come0d9ce82014-04-23 04:00:17 +00002560void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2561 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002562
2563 SkPoint textOffset = SkPoint::Make(0, constY);
2564
halcanary96fcdcc2015-08-27 07:41:13 -07002565 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002566
reed@android.com8a1c16f2008-12-17 15:59:43 +00002567 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002568 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002569 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002570 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002571 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002572
reed@google.com4e2b3d32011-04-07 14:18:59 +00002573 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002574}
2575
reed@google.come0d9ce82014-04-23 04:00:17 +00002576void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2577 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002578 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002579
reed@android.com8a1c16f2008-12-17 15:59:43 +00002580 while (iter.next()) {
2581 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002582 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002583 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002584
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002585 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002586}
2587
fmalita00d5c2c2014-08-21 08:53:26 -07002588void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2589 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002590
fmalita85d5eb92015-03-04 11:20:12 -08002591 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002592 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002593 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002594 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002595 SkRect tmp;
2596 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2597 return;
2598 }
2599 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002600 }
2601
fmalita024f9962015-03-03 19:08:17 -08002602 // We cannot filter in the looper as we normally do, because the paint is
2603 // incomplete at this point (text-related attributes are embedded within blob run paints).
2604 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002605 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002606
fmalita85d5eb92015-03-04 11:20:12 -08002607 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002608
fmalitaaa1b9122014-08-28 14:32:24 -07002609 while (iter.next()) {
2610 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002611 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002612 }
2613
fmalitaaa1b9122014-08-28 14:32:24 -07002614 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002615
2616 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002617}
2618
reed@google.come0d9ce82014-04-23 04:00:17 +00002619// These will become non-virtual, so they always call the (virtual) onDraw... method
2620void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2621 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002622 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002623 this->onDrawText(text, byteLength, x, y, paint);
2624}
2625void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2626 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002627 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002628 this->onDrawPosText(text, byteLength, pos, paint);
2629}
2630void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2631 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002632 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002633 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2634}
2635void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2636 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002637 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002638 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2639}
fmalita00d5c2c2014-08-21 08:53:26 -07002640void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2641 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002642 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002643 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002644 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002645}
reed@google.come0d9ce82014-04-23 04:00:17 +00002646
reed41af9662015-01-05 07:49:08 -08002647void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2648 const SkPoint verts[], const SkPoint texs[],
2649 const SkColor colors[], SkXfermode* xmode,
2650 const uint16_t indices[], int indexCount,
2651 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002652 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002653 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002654
reed@android.com8a1c16f2008-12-17 15:59:43 +00002655 while (iter.next()) {
2656 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002657 colors, xmode, indices, indexCount,
2658 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002659 }
reed@google.com4b226022011-01-11 18:32:13 +00002660
reed@google.com4e2b3d32011-04-07 14:18:59 +00002661 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002662}
2663
dandovb3c9d1c2014-08-12 08:34:29 -07002664void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2665 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002666 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002667 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002668 return;
2669 }
mtklein6cfa73a2014-08-13 13:33:49 -07002670
dandovecfff212014-08-04 10:02:00 -07002671 // Since a patch is always within the convex hull of the control points, we discard it when its
2672 // bounding rectangle is completely outside the current clip.
2673 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002674 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002675 if (this->quickReject(bounds)) {
2676 return;
2677 }
mtklein6cfa73a2014-08-13 13:33:49 -07002678
dandovb3c9d1c2014-08-12 08:34:29 -07002679 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2680}
2681
2682void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2683 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2684
halcanary96fcdcc2015-08-27 07:41:13 -07002685 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002686
dandovecfff212014-08-04 10:02:00 -07002687 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002688 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002689 }
mtklein6cfa73a2014-08-13 13:33:49 -07002690
dandovecfff212014-08-04 10:02:00 -07002691 LOOPER_END
2692}
2693
reeda8db7282015-07-07 10:22:31 -07002694void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002695 RETURN_ON_NULL(dr);
2696 if (x || y) {
2697 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2698 this->onDrawDrawable(dr, &matrix);
2699 } else {
2700 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002701 }
2702}
2703
reeda8db7282015-07-07 10:22:31 -07002704void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002705 RETURN_ON_NULL(dr);
2706 if (matrix && matrix->isIdentity()) {
2707 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002708 }
reede3b38ce2016-01-08 09:18:44 -08002709 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002710}
2711
2712void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2713 SkRect bounds = dr->getBounds();
2714 if (matrix) {
2715 matrix->mapRect(&bounds);
2716 }
2717 if (this->quickReject(bounds)) {
2718 return;
2719 }
2720 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002721}
2722
reed71c3c762015-06-24 10:29:17 -07002723void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2724 const SkColor colors[], int count, SkXfermode::Mode mode,
2725 const SkRect* cull, const SkPaint* paint) {
2726 if (cull && this->quickReject(*cull)) {
2727 return;
2728 }
2729
2730 SkPaint pnt;
2731 if (paint) {
2732 pnt = *paint;
2733 }
2734
halcanary96fcdcc2015-08-27 07:41:13 -07002735 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002736 while (iter.next()) {
2737 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2738 }
2739 LOOPER_END
2740}
2741
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742//////////////////////////////////////////////////////////////////////////////
2743// These methods are NOT virtual, and therefore must call back into virtual
2744// methods, rather than actually drawing themselves.
2745//////////////////////////////////////////////////////////////////////////////
2746
2747void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002748 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002749 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002750 SkPaint paint;
2751
2752 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002753 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002754 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002755 }
2756 this->drawPaint(paint);
2757}
2758
reed@android.com845fdac2009-06-23 03:01:32 +00002759void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002760 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002761 SkPaint paint;
2762
2763 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002764 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002765 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766 }
2767 this->drawPaint(paint);
2768}
2769
2770void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002771 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002773
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774 pt.set(x, y);
2775 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2776}
2777
2778void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002779 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780 SkPoint pt;
2781 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002782
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783 pt.set(x, y);
2784 paint.setColor(color);
2785 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2786}
2787
2788void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2789 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002790 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002792
reed@android.com8a1c16f2008-12-17 15:59:43 +00002793 pts[0].set(x0, y0);
2794 pts[1].set(x1, y1);
2795 this->drawPoints(kLines_PointMode, 2, pts, paint);
2796}
2797
2798void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2799 SkScalar right, SkScalar bottom,
2800 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002801 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002802 SkRect r;
2803
2804 r.set(left, top, right, bottom);
2805 this->drawRect(r, paint);
2806}
2807
2808void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2809 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002810 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002811 if (radius < 0) {
2812 radius = 0;
2813 }
2814
2815 SkRect r;
2816 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002817 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002818}
2819
2820void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2821 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002822 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823 if (rx > 0 && ry > 0) {
2824 if (paint.canComputeFastBounds()) {
2825 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002826 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002827 return;
2828 }
2829 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002830 SkRRect rrect;
2831 rrect.setRectXY(r, rx, ry);
2832 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833 } else {
2834 this->drawRect(r, paint);
2835 }
2836}
2837
reed@android.com8a1c16f2008-12-17 15:59:43 +00002838void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2839 SkScalar sweepAngle, bool useCenter,
2840 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002841 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2843 this->drawOval(oval, paint);
2844 } else {
2845 SkPath path;
2846 if (useCenter) {
2847 path.moveTo(oval.centerX(), oval.centerY());
2848 }
2849 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2850 if (useCenter) {
2851 path.close();
2852 }
2853 this->drawPath(path, paint);
2854 }
2855}
2856
2857void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2858 const SkPath& path, SkScalar hOffset,
2859 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002860 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002861 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002862
reed@android.com8a1c16f2008-12-17 15:59:43 +00002863 matrix.setTranslate(hOffset, vOffset);
2864 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2865}
2866
reed@android.comf76bacf2009-05-13 14:00:33 +00002867///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002868
2869/**
2870 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2871 * against the playback cost of recursing into the subpicture to get at its actual ops.
2872 *
2873 * For now we pick a conservatively small value, though measurement (and other heuristics like
2874 * the type of ops contained) may justify changing this value.
2875 */
2876#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002877
reedd5fa1a42014-08-09 11:08:05 -07002878void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002879 RETURN_ON_NULL(picture);
2880
reed1c2c4412015-04-30 13:09:24 -07002881 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002882 if (matrix && matrix->isIdentity()) {
2883 matrix = nullptr;
2884 }
2885 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2886 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2887 picture->playback(this);
2888 } else {
2889 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002890 }
2891}
robertphillips9b14f262014-06-04 05:40:44 -07002892
reedd5fa1a42014-08-09 11:08:05 -07002893void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2894 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002895 if (!paint || paint->canComputeFastBounds()) {
2896 SkRect bounds = picture->cullRect();
2897 if (paint) {
2898 paint->computeFastBounds(bounds, &bounds);
2899 }
2900 if (matrix) {
2901 matrix->mapRect(&bounds);
2902 }
2903 if (this->quickReject(bounds)) {
2904 return;
2905 }
2906 }
2907
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002908 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002909 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002910 // Canvas has to first give the device the opportunity to render
2911 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002912 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002913 return; // the device has rendered the entire picture
2914 }
2915 }
2916
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002917 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002918 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002919}
2920
reed@android.com8a1c16f2008-12-17 15:59:43 +00002921///////////////////////////////////////////////////////////////////////////////
2922///////////////////////////////////////////////////////////////////////////////
2923
2924SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002925 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002926
2927 SkASSERT(canvas);
2928
2929 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2930 fDone = !fImpl->next();
2931}
2932
2933SkCanvas::LayerIter::~LayerIter() {
2934 fImpl->~SkDrawIter();
2935}
2936
2937void SkCanvas::LayerIter::next() {
2938 fDone = !fImpl->next();
2939}
2940
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002941SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002942 return fImpl->getDevice();
2943}
2944
2945const SkMatrix& SkCanvas::LayerIter::matrix() const {
2946 return fImpl->getMatrix();
2947}
2948
2949const SkPaint& SkCanvas::LayerIter::paint() const {
2950 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002951 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002952 paint = &fDefaultPaint;
2953 }
2954 return *paint;
2955}
2956
2957const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2958int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2959int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002960
2961///////////////////////////////////////////////////////////////////////////////
2962
fmalitac3b589a2014-06-05 12:40:07 -07002963SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002964
2965///////////////////////////////////////////////////////////////////////////////
2966
2967static bool supported_for_raster_canvas(const SkImageInfo& info) {
2968 switch (info.alphaType()) {
2969 case kPremul_SkAlphaType:
2970 case kOpaque_SkAlphaType:
2971 break;
2972 default:
2973 return false;
2974 }
2975
2976 switch (info.colorType()) {
2977 case kAlpha_8_SkColorType:
2978 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002979 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002980 break;
2981 default:
2982 return false;
2983 }
2984
2985 return true;
2986}
2987
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002988SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2989 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002990 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002991 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002992
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002993 SkBitmap bitmap;
2994 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002995 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002996 }
halcanary385fe4d2015-08-26 13:07:48 -07002997 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002998}
reedd5fa1a42014-08-09 11:08:05 -07002999
3000///////////////////////////////////////////////////////////////////////////////
3001
3002SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003003 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003004 : fCanvas(canvas)
3005 , fSaveCount(canvas->getSaveCount())
3006{
bsalomon49f085d2014-09-05 13:34:00 -07003007 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003008 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003009 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003010 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003011 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003012 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003013 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003014 canvas->save();
3015 }
mtklein6cfa73a2014-08-13 13:33:49 -07003016
bsalomon49f085d2014-09-05 13:34:00 -07003017 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003018 canvas->concat(*matrix);
3019 }
3020}
3021
3022SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3023 fCanvas->restoreToCount(fSaveCount);
3024}