blob: f0476cd183dea71d66e3651d204025183f9ccee3 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
bungemand3ebb482015-08-05 13:57:49 -07008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
bungemand3ebb482015-08-05 13:57:49 -070013#include "SkDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080018#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070019#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080020#include "SkImage_Base.h"
21#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000022#include "SkMetaData.h"
reed4c21dc52015-06-25 12:32:03 -070023#include "SkNinePatchIter.h"
reedc83a2972015-07-16 07:40:45 -070024#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070025#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000026#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000027#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080028#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000029#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000030#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000031#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070032#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000033#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000034#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080035#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070036
37#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000039#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080040#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000041#include "GrRenderTarget.h"
robertphillips7354a4b2015-12-16 05:08:27 -080042#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000043#endif
44
reede3b38ce2016-01-08 09:18:44 -080045#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
46
reedc83a2972015-07-16 07:40:45 -070047/*
48 * Return true if the drawing this rect would hit every pixels in the canvas.
49 *
50 * Returns false if
51 * - rect does not contain the canvas' bounds
52 * - paint is not fill
53 * - paint would blur or otherwise change the coverage of the rect
54 */
55bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
56 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070057 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
58 (int)kNone_ShaderOverrideOpacity,
59 "need_matching_enums0");
60 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
61 (int)kOpaque_ShaderOverrideOpacity,
62 "need_matching_enums1");
63 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
64 (int)kNotOpaque_ShaderOverrideOpacity,
65 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070066
67 const SkISize size = this->getBaseLayerSize();
68 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
69 if (!this->getClipStack()->quickContains(bounds)) {
70 return false;
71 }
72
73 if (rect) {
74 if (!this->getTotalMatrix().rectStaysRect()) {
75 return false; // conservative
76 }
77
78 SkRect devRect;
79 this->getTotalMatrix().mapRect(&devRect, *rect);
fmalita8c0144c2015-07-22 05:56:16 -070080 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070081 return false;
82 }
83 }
84
85 if (paint) {
86 SkPaint::Style paintStyle = paint->getStyle();
87 if (!(paintStyle == SkPaint::kFill_Style ||
88 paintStyle == SkPaint::kStrokeAndFill_Style)) {
89 return false;
90 }
91 if (paint->getMaskFilter() || paint->getLooper()
92 || paint->getPathEffect() || paint->getImageFilter()) {
93 return false; // conservative
94 }
95 }
96 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
97}
98
99///////////////////////////////////////////////////////////////////////////////////////////////////
100
reedd990e2f2014-12-22 11:58:30 -0800101static bool gIgnoreSaveLayerBounds;
102void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
103 gIgnoreSaveLayerBounds = ignore;
104}
105bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
106 return gIgnoreSaveLayerBounds;
107}
108
reed0acf1b42014-12-22 16:12:38 -0800109static bool gTreatSpriteAsBitmap;
110void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
111 gTreatSpriteAsBitmap = spriteAsBitmap;
112}
113bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
114 return gTreatSpriteAsBitmap;
115}
116
reed@google.comda17f752012-08-16 18:27:05 +0000117// experimental for faster tiled drawing...
118//#define SK_ENABLE_CLIP_QUICKREJECT
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119//#define SK_TRACE_SAVERESTORE
120
121#ifdef SK_TRACE_SAVERESTORE
122 static int gLayerCounter;
123 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
124 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
125
126 static int gRecCounter;
127 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
128 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
129
130 static int gCanvasCounter;
131 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
132 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
133#else
134 #define inc_layer()
135 #define dec_layer()
136 #define inc_rec()
137 #define dec_rec()
138 #define inc_canvas()
139 #define dec_canvas()
140#endif
141
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000142typedef SkTLazy<SkPaint> SkLazyPaint;
143
reedc83a2972015-07-16 07:40:45 -0700144void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000145 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700146 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
147 ? SkSurface::kDiscard_ContentChangeMode
148 : SkSurface::kRetain_ContentChangeMode);
149 }
150}
151
152void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
153 ShaderOverrideOpacity overrideOpacity) {
154 if (fSurfaceBase) {
155 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
156 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
157 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
158 // and therefore we don't care which mode we're in.
159 //
160 if (fSurfaceBase->outstandingImageSnapshot()) {
161 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
162 mode = SkSurface::kDiscard_ContentChangeMode;
163 }
164 }
165 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000166 }
167}
168
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170
reed4a8126e2014-09-22 07:29:03 -0700171static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
172 const uint32_t propFlags = props.flags();
173 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
174 flags &= ~SkPaint::kDither_Flag;
175 }
176 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
177 flags &= ~SkPaint::kAntiAlias_Flag;
178 }
179 return flags;
180}
181
182///////////////////////////////////////////////////////////////////////////////
183
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000184/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 The clip/matrix/proc are fields that reflect the top of the save/restore
186 stack. Whenever the canvas changes, it marks a dirty flag, and then before
187 these are used (assuming we're not on a layer) we rebuild these cache
188 values: they reflect the top of the save stack, but translated and clipped
189 by the device's XY offset and bitmap-bounds.
190*/
191struct DeviceCM {
192 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000193 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000194 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000195 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700196 const SkMatrix* fMatrix;
197 SkMatrix fMatrixStorage;
198 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199
reed96e657d2015-03-10 17:30:07 -0700200 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed86a17e72015-05-14 12:25:22 -0700201 bool conservativeRasterClip, bool deviceIsBitmapDevice)
halcanary96fcdcc2015-08-27 07:41:13 -0700202 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700203 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700204 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700205 {
halcanary96fcdcc2015-08-27 07:41:13 -0700206 if (nullptr != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000208 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 }
reed@google.com4b226022011-01-11 18:32:13 +0000210 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700211 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000212 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000214 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700215 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000216 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 fDevice->unref();
218 }
halcanary385fe4d2015-08-26 13:07:48 -0700219 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000220 }
reed@google.com4b226022011-01-11 18:32:13 +0000221
mtkleinfeaadee2015-04-08 11:25:48 -0700222 void reset(const SkIRect& bounds) {
223 SkASSERT(!fPaint);
224 SkASSERT(!fNext);
225 SkASSERT(fDevice);
226 fClip.setRect(bounds);
227 }
228
reed@google.com045e62d2011-10-24 12:19:46 +0000229 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
230 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000231 int x = fDevice->getOrigin().x();
232 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 int width = fDevice->width();
234 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000235
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 if ((x | y) == 0) {
237 fMatrix = &totalMatrix;
238 fClip = totalClip;
239 } else {
240 fMatrixStorage = totalMatrix;
241 fMatrixStorage.postTranslate(SkIntToScalar(-x),
242 SkIntToScalar(-y));
243 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 totalClip.translate(-x, -y, &fClip);
246 }
247
reed@google.com045e62d2011-10-24 12:19:46 +0000248 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249
250 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000251
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000253 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 SkRegion::kDifference_Op);
255 }
reed@google.com4b226022011-01-11 18:32:13 +0000256
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000257 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
258
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259#ifdef SK_DEBUG
260 if (!fClip.isEmpty()) {
261 SkIRect deviceR;
262 deviceR.set(0, 0, width, height);
263 SkASSERT(deviceR.contains(fClip.getBounds()));
264 }
265#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000266 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267};
268
269/* This is the record we keep for each save/restore level in the stack.
270 Since a level optionally copies the matrix and/or stack, we have pointers
271 for these fields. If the value is copied for this level, the copy is
272 stored in the ...Storage field, and the pointer points to that. If the
273 value is not copied for this level, we ignore ...Storage, and just point
274 at the corresponding value in the previous level in the stack.
275*/
276class SkCanvas::MCRec {
277public:
reed1f836ee2014-07-07 07:49:34 -0700278 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700279 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 /* If there are any layers in the stack, this points to the top-most
281 one that is at or below this level in the stack (so we know what
282 bitmap/device to draw into from this level. This value is NOT
283 reference counted, since the real owner is either our fLayer field,
284 or a previous one in a lower level.)
285 */
reed2ff1fce2014-12-11 07:07:37 -0800286 DeviceCM* fTopLayer;
287 SkRasterClip fRasterClip;
288 SkMatrix fMatrix;
289 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290
reedd9544982014-09-09 18:46:22 -0700291 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700292 fFilter = nullptr;
293 fLayer = nullptr;
294 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800295 fMatrix.reset();
296 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700297
reedd9544982014-09-09 18:46:22 -0700298 // don't bother initializing fNext
299 inc_rec();
300 }
reed2ff1fce2014-12-11 07:07:37 -0800301 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700302 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700303 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700304 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800305 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700306
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307 // don't bother initializing fNext
308 inc_rec();
309 }
310 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000311 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700312 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 dec_rec();
314 }
mtkleinfeaadee2015-04-08 11:25:48 -0700315
316 void reset(const SkIRect& bounds) {
317 SkASSERT(fLayer);
318 SkASSERT(fDeferredSaveCount == 0);
319
320 fMatrix.reset();
321 fRasterClip.setRect(bounds);
322 fLayer->reset(bounds);
323 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324};
325
326class SkDrawIter : public SkDraw {
327public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000328 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000329 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000330 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 canvas->updateDeviceCMCache();
332
reed687fa1c2015-04-07 08:00:56 -0700333 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000335 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 }
reed@google.com4b226022011-01-11 18:32:13 +0000337
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 bool next() {
339 // skip over recs with empty clips
340 if (fSkipEmptyClips) {
341 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
342 fCurrLayer = fCurrLayer->fNext;
343 }
344 }
345
reed@google.comf68c5e22012-02-24 16:38:58 +0000346 const DeviceCM* rec = fCurrLayer;
347 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348
349 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000350 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
351 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700353 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700354 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700355 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000357 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358
359 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700360 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000361
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 return true;
363 }
364 return false;
365 }
reed@google.com4b226022011-01-11 18:32:13 +0000366
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000367 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000368 int getX() const { return fDevice->getOrigin().x(); }
369 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 const SkMatrix& getMatrix() const { return *fMatrix; }
371 const SkRegion& getClip() const { return *fClip; }
372 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000373
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374private:
375 SkCanvas* fCanvas;
376 const DeviceCM* fCurrLayer;
377 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 SkBool8 fSkipEmptyClips;
379
380 typedef SkDraw INHERITED;
381};
382
383/////////////////////////////////////////////////////////////////////////////
384
reeddbc3cef2015-04-29 12:18:57 -0700385static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
386 return lazy->isValid() ? lazy->get() : lazy->set(orig);
387}
388
389/**
390 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700391 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700392 */
393static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700394 SkImageFilter* imgf = paint.getImageFilter();
395 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700396 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700397 }
398
399 SkColorFilter* imgCF;
400 if (!imgf->asAColorFilter(&imgCF)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700401 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700402 }
403
404 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700405 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700406 // there is no existing paint colorfilter, so we can just return the imagefilter's
407 return imgCF;
408 }
409
410 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
411 // and we need to combine them into a single colorfilter.
412 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
413 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700414}
415
senorblanco87e066e2015-10-28 11:23:36 -0700416/**
417 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
418 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
419 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
420 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
421 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
422 * conservative "effective" bounds based on the settings in the paint... with one exception. This
423 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
424 * deliberately ignored.
425 */
426static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
427 const SkRect& rawBounds,
428 SkRect* storage) {
429 SkPaint tmpUnfiltered(paint);
430 tmpUnfiltered.setImageFilter(nullptr);
431 if (tmpUnfiltered.canComputeFastBounds()) {
432 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
433 } else {
434 return rawBounds;
435 }
436}
437
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438class AutoDrawLooper {
439public:
senorblanco87e066e2015-10-28 11:23:36 -0700440 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
441 // paint. It's used to determine the size of the offscreen layer for filters.
442 // If null, the clip will be used instead.
reed4a8126e2014-09-22 07:29:03 -0700443 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000444 bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700445 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000446 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800447#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800449#else
450 fFilter = nullptr;
451#endif
reed4a8126e2014-09-22 07:29:03 -0700452 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000453 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700454 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000455 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456
reeddbc3cef2015-04-29 12:18:57 -0700457 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
458 if (simplifiedCF) {
459 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
460 paint->setColorFilter(simplifiedCF)->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700461 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700462 fPaint = paint;
463 }
464
465 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700466 /**
467 * We implement ImageFilters for a given draw by creating a layer, then applying the
468 * imagefilter to the pixels of that layer (its backing surface/image), and then
469 * we call restore() to xfer that layer to the main canvas.
470 *
471 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
472 * 2. Generate the src pixels:
473 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
474 * return (fPaint). We then draw the primitive (using srcover) into a cleared
475 * buffer/surface.
476 * 3. Restore the layer created in #1
477 * The imagefilter is passed the buffer/surface from the layer (now filled with the
478 * src pixels of the primitive). It returns a new "filtered" buffer, which we
479 * draw onto the previous layer using the xfermode from the original paint.
480 */
reed@google.com8926b162012-03-23 15:36:36 +0000481 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700482 tmp.setImageFilter(fPaint->getImageFilter());
483 tmp.setXfermode(fPaint->getXfermode());
senorblanco87e066e2015-10-28 11:23:36 -0700484 SkRect storage;
485 if (rawBounds) {
486 // Make rawBounds include all paint outsets except for those due to image filters.
487 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
488 }
reedbfd5f172016-01-07 11:28:08 -0800489 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700490 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700491 fTempLayerForImageFilter = true;
492 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000493 }
494
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000495 if (SkDrawLooper* looper = paint.getLooper()) {
496 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
497 looper->contextSize());
498 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000499 fIsSimple = false;
500 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700501 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000502 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700503 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000504 }
piotaixrb5fae932014-09-24 13:03:30 -0700505
reed4a8126e2014-09-22 07:29:03 -0700506 uint32_t oldFlags = paint.getFlags();
507 fNewPaintFlags = filter_paint_flags(props, oldFlags);
508 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700509 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700510 paint->setFlags(fNewPaintFlags);
511 fPaint = paint;
512 // if we're not simple, doNext() will take care of calling setFlags()
513 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700517 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000518 fCanvas->internalRestore();
519 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000520 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000522
reed@google.com4e2b3d32011-04-07 14:18:59 +0000523 const SkPaint& paint() const {
524 SkASSERT(fPaint);
525 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000527
reed@google.com129ec222012-05-15 13:24:09 +0000528 bool next(SkDrawFilter::Type drawType) {
529 if (fDone) {
530 return false;
531 } else if (fIsSimple) {
532 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000533 return !fPaint->nothingToDraw();
534 } else {
535 return this->doNext(drawType);
536 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000537 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000538
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539private:
reeddbc3cef2015-04-29 12:18:57 -0700540 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
541 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000542 SkCanvas* fCanvas;
543 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000544 SkDrawFilter* fFilter;
545 const SkPaint* fPaint;
546 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700547 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700548 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000549 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000550 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000551 SkDrawLooper::Context* fLooperContext;
552 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000553
554 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555};
556
reed@google.com129ec222012-05-15 13:24:09 +0000557bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700558 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000559 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700560 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000561
reeddbc3cef2015-04-29 12:18:57 -0700562 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
563 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700564 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000565
reed5c476fb2015-04-20 08:04:21 -0700566 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700567 paint->setImageFilter(nullptr);
568 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000569 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000570
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000571 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000572 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000573 return false;
574 }
575 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000576 if (!fFilter->filter(paint, drawType)) {
577 fDone = true;
578 return false;
579 }
halcanary96fcdcc2015-08-27 07:41:13 -0700580 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000581 // no looper means we only draw once
582 fDone = true;
583 }
584 }
585 fPaint = paint;
586
587 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000588 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000589 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000590 }
591
592 // call this after any possible paint modifiers
593 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700594 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000595 return false;
596 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000597 return true;
598}
599
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600////////// macros to place around the internal draw calls //////////////////
601
reed262a71b2015-12-05 13:07:27 -0800602#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
603 this->predrawNotify(); \
604 AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \
605 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
606 SkDrawIter iter(this);
607
608
reed@google.com8926b162012-03-23 15:36:36 +0000609#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000610 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700611 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000612 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000613 SkDrawIter iter(this);
614
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000615#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000616 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700617 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000618 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000620
reedc83a2972015-07-16 07:40:45 -0700621#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
622 this->predrawNotify(bounds, &paint, auxOpaque); \
623 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
624 while (looper.next(type)) { \
625 SkDrawIter iter(this);
626
reed@google.com4e2b3d32011-04-07 14:18:59 +0000627#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628
629////////////////////////////////////////////////////////////////////////////
630
mtkleinfeaadee2015-04-08 11:25:48 -0700631void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
632 this->restoreToCount(1);
633 fCachedLocalClipBounds.setEmpty();
634 fCachedLocalClipBoundsDirty = true;
635 fClipStack->reset();
636 fMCRec->reset(bounds);
637
638 // We're peering through a lot of structs here. Only at this scope do we
639 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
640 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
641}
642
reedd9544982014-09-09 18:46:22 -0700643SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800644 if (device && device->forceConservativeRasterClip()) {
645 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
646 }
647 // Since init() is only called once by our constructors, it is safe to perform this
648 // const-cast.
649 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
650
reed@google.comc0784db2013-12-13 21:16:12 +0000651 fCachedLocalClipBounds.setEmpty();
652 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000653 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000654 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700655 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800656 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700657 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658
halcanary385fe4d2015-08-26 13:07:48 -0700659 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700660
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700662 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663
reeda499f902015-05-01 09:34:31 -0700664 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
665 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700666 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700667
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669
halcanary96fcdcc2015-08-27 07:41:13 -0700670 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000671
reedf92c8662014-08-18 08:02:43 -0700672 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700673 // The root device and the canvas should always have the same pixel geometry
674 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700675 device->onAttachToCanvas(this);
676 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800677 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700678 }
679 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680}
681
reed@google.comcde92112011-07-06 20:00:52 +0000682SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000683 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700684 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800685 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000686{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000687 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000688
halcanary96fcdcc2015-08-27 07:41:13 -0700689 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000690}
691
reedd9544982014-09-09 18:46:22 -0700692static SkBitmap make_nopixels(int width, int height) {
693 SkBitmap bitmap;
694 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
695 return bitmap;
696}
697
698class SkNoPixelsBitmapDevice : public SkBitmapDevice {
699public:
robertphillipsfcf78292015-06-19 11:49:52 -0700700 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
701 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800702 {
703 this->setOrigin(bounds.x(), bounds.y());
704 }
reedd9544982014-09-09 18:46:22 -0700705
706private:
piotaixrb5fae932014-09-24 13:03:30 -0700707
reedd9544982014-09-09 18:46:22 -0700708 typedef SkBitmapDevice INHERITED;
709};
710
reed96a857e2015-01-25 10:33:58 -0800711SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000712 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800713 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800714 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000715{
716 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700717
halcanary385fe4d2015-08-26 13:07:48 -0700718 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
719 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700720}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000721
reed78e27682014-11-19 08:04:34 -0800722SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700723 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700724 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800725 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700726{
727 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700728
halcanary385fe4d2015-08-26 13:07:48 -0700729 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700730}
731
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000732SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000733 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700734 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800735 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000736{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000737 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700738
reedd9544982014-09-09 18:46:22 -0700739 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740}
741
robertphillipsfcf78292015-06-19 11:49:52 -0700742SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
743 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700744 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800745 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700746{
747 inc_canvas();
748
749 this->init(device, flags);
750}
751
reed4a8126e2014-09-22 07:29:03 -0700752SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700753 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700754 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800755 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700756{
757 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700758
halcanary385fe4d2015-08-26 13:07:48 -0700759 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700760 this->init(device, kDefault_InitFlags);
761}
reed29c857d2014-09-21 10:25:07 -0700762
reed4a8126e2014-09-22 07:29:03 -0700763SkCanvas::SkCanvas(const SkBitmap& bitmap)
764 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
765 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800766 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700767{
768 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700769
halcanary385fe4d2015-08-26 13:07:48 -0700770 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700771 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772}
773
774SkCanvas::~SkCanvas() {
775 // free up the contents of our deque
776 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000777
reed@android.com8a1c16f2008-12-17 15:59:43 +0000778 this->internalRestore(); // restore the last, since we're going away
779
halcanary385fe4d2015-08-26 13:07:48 -0700780 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000781
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782 dec_canvas();
783}
784
fmalita53d9f1c2016-01-25 06:23:54 -0800785#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786SkDrawFilter* SkCanvas::getDrawFilter() const {
787 return fMCRec->fFilter;
788}
789
790SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700791 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
793 return filter;
794}
fmalita77650002016-01-21 18:47:11 -0800795#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000797SkMetaData& SkCanvas::getMetaData() {
798 // metadata users are rare, so we lazily allocate it. If that changes we
799 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700800 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000801 fMetaData = new SkMetaData;
802 }
803 return *fMetaData;
804}
805
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806///////////////////////////////////////////////////////////////////////////////
807
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000808void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000809 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000810 if (device) {
811 device->flush();
812 }
813}
814
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000815SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000816 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000817 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
818}
819
senorblancoafc7cce2016-02-02 18:44:15 -0800820SkIRect SkCanvas::getTopLayerBounds() const {
821 SkBaseDevice* d = this->getTopDevice();
822 if (!d) {
823 return SkIRect::MakeEmpty();
824 }
825 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
826}
827
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000828SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000829 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000830 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831 SkASSERT(rec && rec->fLayer);
832 return rec->fLayer->fDevice;
833}
834
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000835SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000836 if (updateMatrixClip) {
837 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
838 }
reed@google.com9266fed2011-03-30 00:18:03 +0000839 return fMCRec->fTopLayer->fDevice;
840}
841
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000842bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
843 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
844 return false;
845 }
846
847 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700848 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700849 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000850 return false;
851 }
852 weAllocated = true;
853 }
854
reedcf01e312015-05-23 19:14:51 -0700855 SkAutoPixmapUnlock unlocker;
856 if (bitmap->requestLock(&unlocker)) {
857 const SkPixmap& pm = unlocker.pixmap();
858 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
859 return true;
860 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000861 }
862
863 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700864 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000865 }
866 return false;
867}
reed@google.com51df9e32010-12-23 19:29:18 +0000868
bsalomon@google.comc6980972011-11-02 19:57:21 +0000869bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000870 SkIRect r = srcRect;
871 const SkISize size = this->getBaseLayerSize();
872 if (!r.intersect(0, 0, size.width(), size.height())) {
873 bitmap->reset();
874 return false;
875 }
876
reed84825042014-09-02 12:50:45 -0700877 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000878 // bitmap will already be reset.
879 return false;
880 }
881 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
882 bitmap->reset();
883 return false;
884 }
885 return true;
886}
887
reed96472de2014-12-10 09:53:42 -0800888bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000889 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000890 if (!device) {
891 return false;
892 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000893 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800894
reed96472de2014-12-10 09:53:42 -0800895 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
896 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000897 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000898 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000899
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000900 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800901 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000902}
903
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000904bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
905 if (bitmap.getTexture()) {
906 return false;
907 }
reedcf01e312015-05-23 19:14:51 -0700908
909 SkAutoPixmapUnlock unlocker;
910 if (bitmap.requestLock(&unlocker)) {
911 const SkPixmap& pm = unlocker.pixmap();
912 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000913 }
914 return false;
915}
916
917bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
918 int x, int y) {
919 switch (origInfo.colorType()) {
920 case kUnknown_SkColorType:
921 case kIndex_8_SkColorType:
922 return false;
923 default:
924 break;
925 }
halcanary96fcdcc2015-08-27 07:41:13 -0700926 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000927 return false;
928 }
929
930 const SkISize size = this->getBaseLayerSize();
931 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
932 if (!target.intersect(0, 0, size.width(), size.height())) {
933 return false;
934 }
935
936 SkBaseDevice* device = this->getDevice();
937 if (!device) {
938 return false;
939 }
940
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000941 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700942 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000943
944 // if x or y are negative, then we have to adjust pixels
945 if (x > 0) {
946 x = 0;
947 }
948 if (y > 0) {
949 y = 0;
950 }
951 // here x,y are either 0 or negative
952 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
953
reed4af35f32014-06-27 17:47:49 -0700954 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700955 const bool completeOverwrite = info.dimensions() == size;
956 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700957
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000958 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000959 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000960}
reed@google.com51df9e32010-12-23 19:29:18 +0000961
junov@google.com4370aed2012-01-18 16:21:08 +0000962SkCanvas* SkCanvas::canvasForDrawIter() {
963 return this;
964}
965
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966//////////////////////////////////////////////////////////////////////////////
967
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968void SkCanvas::updateDeviceCMCache() {
969 if (fDeviceCMDirty) {
970 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700971 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000972 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000973
halcanary96fcdcc2015-08-27 07:41:13 -0700974 if (nullptr == layer->fNext) { // only one layer
975 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000977 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 do {
reed687fa1c2015-04-07 08:00:56 -0700979 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700980 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 }
982 fDeviceCMDirty = false;
983 }
984}
985
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986///////////////////////////////////////////////////////////////////////////////
987
reed2ff1fce2014-12-11 07:07:37 -0800988void SkCanvas::checkForDeferredSave() {
989 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800990 this->doSave();
991 }
992}
993
reedf0090cb2014-11-26 08:55:51 -0800994int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800995#ifdef SK_DEBUG
996 int count = 0;
997 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
998 for (;;) {
999 const MCRec* rec = (const MCRec*)iter.next();
1000 if (!rec) {
1001 break;
1002 }
1003 count += 1 + rec->fDeferredSaveCount;
1004 }
1005 SkASSERT(count == fSaveCount);
1006#endif
1007 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001008}
1009
1010int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001011 fSaveCount += 1;
1012 fMCRec->fDeferredSaveCount += 1;
1013 return this->getSaveCount() - 1; // return our prev value
1014}
1015
1016void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001017 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001018
1019 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1020 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001021 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001022}
1023
1024void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001025 if (fMCRec->fDeferredSaveCount > 0) {
1026 SkASSERT(fSaveCount > 1);
1027 fSaveCount -= 1;
1028 fMCRec->fDeferredSaveCount -= 1;
1029 } else {
1030 // check for underflow
1031 if (fMCStack.count() > 1) {
1032 this->willRestore();
1033 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001034 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001035 this->internalRestore();
1036 this->didRestore();
1037 }
reedf0090cb2014-11-26 08:55:51 -08001038 }
1039}
1040
1041void SkCanvas::restoreToCount(int count) {
1042 // sanity check
1043 if (count < 1) {
1044 count = 1;
1045 }
mtkleinf0f14112014-12-12 08:46:25 -08001046
reedf0090cb2014-11-26 08:55:51 -08001047 int n = this->getSaveCount() - count;
1048 for (int i = 0; i < n; ++i) {
1049 this->restore();
1050 }
1051}
1052
reed2ff1fce2014-12-11 07:07:37 -08001053void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001055 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001057
reed687fa1c2015-04-07 08:00:56 -07001058 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059}
1060
reed4960eee2015-12-18 07:09:18 -08001061bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001062#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001063 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@google.comb93ba452014-03-10 19:47:58 +00001064#else
1065 return true;
1066#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067}
1068
reed4960eee2015-12-18 07:09:18 -08001069bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001070 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001071 SkIRect clipBounds;
1072 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001073 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001074 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001075
reed96e657d2015-03-10 17:30:07 -07001076 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1077
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001078 if (imageFilter) {
reed1d524692016-02-22 05:57:31 -08001079 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblancodb64af32015-12-09 10:11:43 -08001080 if (bounds && !imageFilter->canComputeFastBounds()) {
1081 bounds = nullptr;
1082 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001083 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001084 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001085 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001087
reed96e657d2015-03-10 17:30:07 -07001088 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089 r.roundOut(&ir);
1090 // early exit if the layer's bounds are clipped out
1091 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001092 if (BoundsAffectsClip(saveLayerFlags)) {
reed9b3aa542015-03-11 08:47:12 -07001093 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001094 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001095 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001096 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097 }
1098 } else { // no user bounds, so just use the clip
1099 ir = clipBounds;
1100 }
reed180aec42015-03-11 10:39:04 -07001101 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001102
reed4960eee2015-12-18 07:09:18 -08001103 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001104 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -07001105 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -07001106 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001107 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001108 }
1109
1110 if (intersection) {
1111 *intersection = ir;
1112 }
1113 return true;
1114}
1115
reed4960eee2015-12-18 07:09:18 -08001116
reed4960eee2015-12-18 07:09:18 -08001117int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1118 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001119}
1120
reed70ee31b2015-12-10 13:44:45 -08001121int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001122 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1123}
1124
1125int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1126 SaveLayerRec rec(origRec);
1127 if (gIgnoreSaveLayerBounds) {
1128 rec.fBounds = nullptr;
1129 }
1130 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1131 fSaveCount += 1;
1132 this->internalSaveLayer(rec, strategy);
1133 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001134}
1135
reedbfd5f172016-01-07 11:28:08 -08001136static void draw_filter_into_device(SkBaseDevice* src, const SkImageFilter* filter,
1137 SkBaseDevice* dst, const SkMatrix& ctm) {
robertphillips7354a4b2015-12-16 05:08:27 -08001138
1139 SkBitmap srcBM;
1140
1141#if SK_SUPPORT_GPU
1142 GrRenderTarget* srcRT = src->accessRenderTarget();
1143 if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) {
1144 // When both the src & the dst are on the gpu but the src doesn't have a texture,
1145 // we create a temporary texture for the draw.
1146 // TODO: we should actually only copy the portion of the source needed to apply the image
1147 // filter
1148 GrContext* context = srcRT->getContext();
1149 SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(srcRT->desc(), true));
1150
1151 context->copySurface(tex, srcRT);
1152
1153 GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM);
1154 } else
1155#endif
1156 {
1157 srcBM = src->accessBitmap(false);
1158 }
1159
1160 SkCanvas c(dst);
1161
reedbfd5f172016-01-07 11:28:08 -08001162 SkAutoTUnref<SkImageFilter> localF(filter->newWithLocalMatrix(ctm));
robertphillips7354a4b2015-12-16 05:08:27 -08001163 SkPaint p;
reedbfd5f172016-01-07 11:28:08 -08001164 p.setImageFilter(localF);
1165 const SkScalar x = SkIntToScalar(src->getOrigin().x());
1166 const SkScalar y = SkIntToScalar(src->getOrigin().y());
1167 c.drawBitmap(srcBM, x, y, &p);
robertphillips7354a4b2015-12-16 05:08:27 -08001168}
reed70ee31b2015-12-10 13:44:45 -08001169
reed129ed1c2016-02-22 06:42:31 -08001170static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1171 const SkPaint* paint) {
1172 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1173 // e.g. sRGB or F16, we can remove this check
1174 const bool hasImageFilter = paint && paint->getImageFilter();
1175
1176 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1177 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1178 // force to L32
1179 return SkImageInfo::MakeN32(w, h, alphaType);
1180 } else {
1181 // keep the same characteristics as the prev
1182 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.profileType());
1183 }
1184}
1185
reed4960eee2015-12-18 07:09:18 -08001186void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1187 const SkRect* bounds = rec.fBounds;
1188 const SkPaint* paint = rec.fPaint;
1189 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1190
reed@google.comb93ba452014-03-10 19:47:58 +00001191#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001192 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001193#endif
1194
junov@chromium.orga907ac32012-02-24 21:54:07 +00001195 // do this before we create the layer. We don't call the public save() since
1196 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001197 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001198
1199 fDeviceCMDirty = true;
1200
1201 SkIRect ir;
reed4960eee2015-12-18 07:09:18 -08001202 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001203 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204 }
1205
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001206 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1207 // the clipRectBounds() call above?
1208 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001209 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001210 }
1211
reed4960eee2015-12-18 07:09:18 -08001212 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001213 SkPixelGeometry geo = fProps.pixelGeometry();
1214 if (paint) {
reed76033be2015-03-14 10:54:31 -07001215 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001216 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001217 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001218 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001219 }
1220 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221
reedb2db8982014-11-13 12:41:02 -08001222 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001223 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001224 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001225 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001226 }
reedb2db8982014-11-13 12:41:02 -08001227
reed129ed1c2016-02-22 06:42:31 -08001228 SkImageInfo info = make_layer_info(device->imageInfo(), ir.width(), ir.height(), isOpaque,
1229 paint);
1230
reed61f501f2015-04-29 08:34:00 -07001231 bool forceSpriteOnRestore = false;
1232 {
reed70ee31b2015-12-10 13:44:45 -08001233 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001234 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001235 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001236 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1237 preserveLCDText, false);
reed61f501f2015-04-29 08:34:00 -07001238 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001239 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001240 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001241 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1242 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001243 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001244 SkErrorInternals::SetError(kInternalError_SkError,
1245 "Unable to create device for layer.");
1246 return;
1247 }
1248 forceSpriteOnRestore = true;
1249 }
1250 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001251 }
reed@google.com6f8f2922011-03-04 22:27:10 +00001252 device->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001253
reedbfd5f172016-01-07 11:28:08 -08001254 if (rec.fBackdrop) {
1255 draw_filter_into_device(fMCRec->fTopLayer->fDevice, rec.fBackdrop, device, fMCRec->fMatrix);
robertphillips7354a4b2015-12-16 05:08:27 -08001256 }
1257
halcanary385fe4d2015-08-26 13:07:48 -07001258 DeviceCM* layer =
1259 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260 device->unref();
1261
1262 layer->fNext = fMCRec->fTopLayer;
1263 fMCRec->fLayer = layer;
1264 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265}
1266
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001267int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001268 if (0xFF == alpha) {
1269 return this->saveLayer(bounds, nullptr);
1270 } else {
1271 SkPaint tmpPaint;
1272 tmpPaint.setAlpha(alpha);
1273 return this->saveLayer(bounds, &tmpPaint);
1274 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001275}
1276
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277void SkCanvas::internalRestore() {
1278 SkASSERT(fMCStack.count() != 0);
1279
1280 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001281 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282
reed687fa1c2015-04-07 08:00:56 -07001283 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001284
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001285 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286 DeviceCM* layer = fMCRec->fLayer; // may be null
1287 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001288 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289
1290 // now do the normal restore()
1291 fMCRec->~MCRec(); // balanced in save()
1292 fMCStack.pop_back();
1293 fMCRec = (MCRec*)fMCStack.back();
1294
1295 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1296 since if we're being recorded, we don't want to record this (the
1297 recorder will have already recorded the restore).
1298 */
bsalomon49f085d2014-09-05 13:34:00 -07001299 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001301 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001302 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001303 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001304 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001306 delete layer;
reedb679ca82015-04-07 04:40:48 -07001307 } else {
1308 // we're at the root
reeda499f902015-05-01 09:34:31 -07001309 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001310 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001312 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313}
1314
reed4a8126e2014-09-22 07:29:03 -07001315SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001316 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001317 props = &fProps;
1318 }
1319 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001320}
1321
reed4a8126e2014-09-22 07:29:03 -07001322SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001323 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001324 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001325}
1326
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001327SkImageInfo SkCanvas::imageInfo() const {
1328 SkBaseDevice* dev = this->getDevice();
1329 if (dev) {
1330 return dev->imageInfo();
1331 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001332 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001333 }
1334}
1335
1336const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001337 SkPixmap pmap;
1338 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001339 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001340 }
1341 if (info) {
1342 *info = pmap.info();
1343 }
1344 if (rowBytes) {
1345 *rowBytes = pmap.rowBytes();
1346 }
1347 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001348}
1349
reed884e97c2015-05-26 11:31:54 -07001350bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001351 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001352 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001353}
1354
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001355void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001356 SkPixmap pmap;
1357 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001358 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001359 }
1360 if (info) {
1361 *info = pmap.info();
1362 }
1363 if (rowBytes) {
1364 *rowBytes = pmap.rowBytes();
1365 }
1366 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001367 *origin = this->getTopDevice(false)->getOrigin();
1368 }
reed884e97c2015-05-26 11:31:54 -07001369 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001370}
1371
reed884e97c2015-05-26 11:31:54 -07001372bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001373 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001374 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001375}
1376
reed@android.com8a1c16f2008-12-17 15:59:43 +00001377/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001379void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001380 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001382 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383 paint = &tmp;
1384 }
reed@google.com4b226022011-01-11 18:32:13 +00001385
reed@google.com8926b162012-03-23 15:36:36 +00001386 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001387 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001388 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001389 paint = &looper.paint();
1390 SkImageFilter* filter = paint->getImageFilter();
1391 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001392 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001393 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001394 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001395 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001396 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001397 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001398 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblancodb64af32015-12-09 10:11:43 -08001399 SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
senorblancobe129b22014-08-08 07:14:35 -07001400 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reed4e23cda2016-01-11 10:56:59 -08001401 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
robertphillips48e78462016-02-17 13:57:16 -08001402 if (filter->filterImageDeprecated(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001403 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001404 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001405 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1406 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001407 }
reed61f501f2015-04-29 08:34:00 -07001408 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001409 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001410 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001411 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001412 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001413 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001415 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416}
1417
reed32704672015-12-16 08:27:10 -08001418/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001419
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001420void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001421 SkMatrix m;
1422 m.setTranslate(dx, dy);
1423 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424}
1425
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001426void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001427 SkMatrix m;
1428 m.setScale(sx, sy);
1429 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430}
1431
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001432void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001433 SkMatrix m;
1434 m.setRotate(degrees);
1435 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436}
1437
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001438void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001439 SkMatrix m;
1440 m.setSkew(sx, sy);
1441 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001442}
1443
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001444void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001445 if (matrix.isIdentity()) {
1446 return;
1447 }
1448
reed2ff1fce2014-12-11 07:07:37 -08001449 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001451 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001452 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001453
1454 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001455}
1456
reed86a17e72015-05-14 12:25:22 -07001457void SkCanvas::setMatrix(const SkMatrix& matrix) {
1458 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001459 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001460 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001461 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001462 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001463}
1464
reed@android.com8a1c16f2008-12-17 15:59:43 +00001465void SkCanvas::resetMatrix() {
1466 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001467
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468 matrix.reset();
1469 this->setMatrix(matrix);
1470}
1471
1472//////////////////////////////////////////////////////////////////////////////
1473
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001474void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001475 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001476 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1477 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001478}
1479
1480void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001481#ifdef SK_ENABLE_CLIP_QUICKREJECT
1482 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001483 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001484 return false;
1485 }
1486
reed@google.com3b3e8952012-08-16 20:53:31 +00001487 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001488 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001489 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001490
reed687fa1c2015-04-07 08:00:56 -07001491 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001492 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001493 }
1494 }
1495#endif
1496
bsalomonac8cabd2015-11-20 18:53:07 -08001497 if (!fAllowSoftClip) {
1498 edgeStyle = kHard_ClipEdgeStyle;
1499 }
reed90ba0952015-11-20 13:42:47 -08001500
reedc64eff52015-11-21 12:39:45 -08001501 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1502 SkRect devR;
1503 if (rectStaysRect) {
1504 fMCRec->fMatrix.mapRect(&devR, rect);
1505 }
bsalomonac8cabd2015-11-20 18:53:07 -08001506
reedc64eff52015-11-21 12:39:45 -08001507 // Check if we can quick-accept the clip call (and do nothing)
1508 //
1509 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1510 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1511 // might allow lazy save/restores to eliminate entire save/restore blocks.
1512 //
1513 if (SkRegion::kIntersect_Op == op &&
1514 kHard_ClipEdgeStyle == edgeStyle
1515 && rectStaysRect)
1516 {
1517 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1518#if 0
1519 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1520 rect.left(), rect.top(), rect.right(), rect.bottom());
1521#endif
1522 return;
1523 }
1524 }
1525
1526 AutoValidateClip avc(this);
1527
1528 fDeviceCMDirty = true;
1529 fCachedLocalClipBoundsDirty = true;
1530
1531 if (rectStaysRect) {
1532 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1533 fClipStack->clipDevRect(devR, op, isAA);
senorblancoafc7cce2016-02-02 18:44:15 -08001534 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001535 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001536 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001537 // and clip against that, since it can handle any matrix. However, to
1538 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1539 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001540 SkPath path;
1541
1542 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001543 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001544 }
1545}
1546
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001547void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001548 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001549 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001550 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001551 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1552 } else {
1553 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001554 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001555}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001556
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001557void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001558 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001559 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001560 AutoValidateClip avc(this);
1561
1562 fDeviceCMDirty = true;
1563 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001564 if (!fAllowSoftClip) {
1565 edgeStyle = kHard_ClipEdgeStyle;
1566 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001567
reed687fa1c2015-04-07 08:00:56 -07001568 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001569
senorblancoafc7cce2016-02-02 18:44:15 -08001570 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
robertphillips125f19a2015-11-23 09:00:05 -08001571 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001572 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001573 }
1574
1575 SkPath path;
1576 path.addRRect(rrect);
1577 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001578 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001579}
1580
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001581void SkCanvas::clipPath(const SkPath& path, 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;
robertphillips39f05382015-11-24 09:30:12 -08001584
1585 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1586 SkRect r;
1587 if (path.isRect(&r)) {
1588 this->onClipRect(r, op, edgeStyle);
1589 return;
1590 }
1591 SkRRect rrect;
1592 if (path.isOval(&r)) {
1593 rrect.setOval(r);
1594 this->onClipRRect(rrect, op, edgeStyle);
1595 return;
1596 }
1597 if (path.isRRect(&rrect)) {
1598 this->onClipRRect(rrect, op, edgeStyle);
1599 return;
1600 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001601 }
robertphillips39f05382015-11-24 09:30:12 -08001602
1603 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001604}
1605
1606void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001607#ifdef SK_ENABLE_CLIP_QUICKREJECT
1608 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001609 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001610 return false;
1611 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001612
reed@google.com3b3e8952012-08-16 20:53:31 +00001613 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001614 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001615 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001616
reed687fa1c2015-04-07 08:00:56 -07001617 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001618 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001619 }
1620 }
1621#endif
1622
reed@google.com5c3d1472011-02-22 19:12:23 +00001623 AutoValidateClip avc(this);
1624
reed@android.com8a1c16f2008-12-17 15:59:43 +00001625 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001626 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001627 if (!fAllowSoftClip) {
1628 edgeStyle = kHard_ClipEdgeStyle;
1629 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001630
1631 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001632 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001633
reed@google.comfe701122011-11-08 19:41:23 +00001634 // Check if the transfomation, or the original path itself
1635 // made us empty. Note this can also happen if we contained NaN
1636 // values. computing the bounds detects this, and will set our
1637 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1638 if (devPath.getBounds().isEmpty()) {
1639 // resetting the path will remove any NaN or other wanky values
1640 // that might upset our scan converter.
1641 devPath.reset();
1642 }
1643
reed@google.com5c3d1472011-02-22 19:12:23 +00001644 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001645 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001646
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001647 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001648 bool clipIsAA = getClipStack()->asPath(&devPath);
1649 if (clipIsAA) {
1650 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001651 }
fmalita1a481fe2015-02-04 07:39:34 -08001652
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001653 op = SkRegion::kReplace_Op;
1654 }
1655
senorblancoafc7cce2016-02-02 18:44:15 -08001656 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657}
1658
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001659void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001660 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001661 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001662}
1663
1664void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001665 AutoValidateClip avc(this);
1666
reed@android.com8a1c16f2008-12-17 15:59:43 +00001667 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001668 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001669
reed@google.com5c3d1472011-02-22 19:12:23 +00001670 // todo: signal fClipStack that we have a region, and therefore (I guess)
1671 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001672 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001673
reed1f836ee2014-07-07 07:49:34 -07001674 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001675}
1676
reed@google.com819c9212011-02-23 18:56:55 +00001677#ifdef SK_DEBUG
1678void SkCanvas::validateClip() const {
1679 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001680 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001681 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001682 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001683 return;
1684 }
1685
reed@google.com819c9212011-02-23 18:56:55 +00001686 SkIRect ir;
1687 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001688 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001689
reed687fa1c2015-04-07 08:00:56 -07001690 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001691 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001692 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001693 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001694 case SkClipStack::Element::kRect_Type:
1695 element->getRect().round(&ir);
1696 tmpClip.op(ir, element->getOp());
1697 break;
1698 case SkClipStack::Element::kEmpty_Type:
1699 tmpClip.setEmpty();
1700 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001701 default: {
1702 SkPath path;
1703 element->asPath(&path);
senorblancoafc7cce2016-02-02 18:44:15 -08001704 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001705 break;
1706 }
reed@google.com819c9212011-02-23 18:56:55 +00001707 }
1708 }
reed@google.com819c9212011-02-23 18:56:55 +00001709}
1710#endif
1711
reed@google.com90c07ea2012-04-13 13:50:27 +00001712void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001713 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001714 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001715
halcanary96fcdcc2015-08-27 07:41:13 -07001716 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001717 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001718 }
1719}
1720
reed@google.com5c3d1472011-02-22 19:12:23 +00001721///////////////////////////////////////////////////////////////////////////////
1722
reed@google.com754de5f2014-02-24 19:38:20 +00001723bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001724 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001725}
1726
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001727bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001728 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001729}
1730
reed@google.com3b3e8952012-08-16 20:53:31 +00001731bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001732 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001733 return true;
1734
reed1f836ee2014-07-07 07:49:34 -07001735 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001736 return true;
1737 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001738
reed1f836ee2014-07-07 07:49:34 -07001739 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001740 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001741 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001742 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001743 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001744 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001745
reed@android.coma380ae42009-07-21 01:17:02 +00001746 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001747 // TODO: should we use | instead, or compare all 4 at once?
1748 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001749 return true;
1750 }
reed@google.comc0784db2013-12-13 21:16:12 +00001751 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001752 return true;
1753 }
1754 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001755 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001756}
1757
reed@google.com3b3e8952012-08-16 20:53:31 +00001758bool SkCanvas::quickReject(const SkPath& path) const {
1759 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001760}
1761
reed@google.com3b3e8952012-08-16 20:53:31 +00001762bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001763 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001764 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001765 return false;
1766 }
1767
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001768 SkMatrix inverse;
1769 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001770 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001771 if (bounds) {
1772 bounds->setEmpty();
1773 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001774 return false;
1775 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001776
bsalomon49f085d2014-09-05 13:34:00 -07001777 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001778 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001779 // adjust it outwards in case we are antialiasing
1780 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001781
reed@google.com8f4d2302013-12-17 16:44:46 +00001782 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1783 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001784 inverse.mapRect(bounds, r);
1785 }
1786 return true;
1787}
1788
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001789bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001790 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001791 if (clip.isEmpty()) {
1792 if (bounds) {
1793 bounds->setEmpty();
1794 }
1795 return false;
1796 }
1797
bsalomon49f085d2014-09-05 13:34:00 -07001798 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001799 *bounds = clip.getBounds();
1800 }
1801 return true;
1802}
1803
reed@android.com8a1c16f2008-12-17 15:59:43 +00001804const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001805 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001806}
1807
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001808const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001809 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001810}
1811
reed@google.com9c135db2014-03-12 18:28:35 +00001812GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1813 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001814 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001815}
1816
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001817GrContext* SkCanvas::getGrContext() {
1818#if SK_SUPPORT_GPU
1819 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001820 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001821 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001822 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001823 return renderTarget->getContext();
1824 }
1825 }
1826#endif
1827
halcanary96fcdcc2015-08-27 07:41:13 -07001828 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001829
1830}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001831
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001832void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1833 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001834 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001835 if (outer.isEmpty()) {
1836 return;
1837 }
1838 if (inner.isEmpty()) {
1839 this->drawRRect(outer, paint);
1840 return;
1841 }
1842
1843 // We don't have this method (yet), but technically this is what we should
1844 // be able to assert...
1845 // SkASSERT(outer.contains(inner));
1846 //
1847 // For now at least check for containment of bounds
1848 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1849
1850 this->onDrawDRRect(outer, inner, paint);
1851}
1852
reed41af9662015-01-05 07:49:08 -08001853// These need to stop being virtual -- clients need to override the onDraw... versions
1854
1855void SkCanvas::drawPaint(const SkPaint& paint) {
1856 this->onDrawPaint(paint);
1857}
1858
1859void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1860 this->onDrawRect(r, paint);
1861}
1862
1863void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1864 this->onDrawOval(r, paint);
1865}
1866
1867void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1868 this->onDrawRRect(rrect, paint);
1869}
1870
1871void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1872 this->onDrawPoints(mode, count, pts, paint);
1873}
1874
1875void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1876 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1877 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1878 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1879 indices, indexCount, paint);
1880}
1881
1882void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1883 this->onDrawPath(path, paint);
1884}
1885
reeda85d4d02015-05-06 12:56:48 -07001886void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001887 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001888 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001889}
1890
reede47829b2015-08-06 10:02:53 -07001891void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1892 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001893 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001894 if (dst.isEmpty() || src.isEmpty()) {
1895 return;
1896 }
1897 this->onDrawImageRect(image, &src, dst, paint, constraint);
1898}
reed41af9662015-01-05 07:49:08 -08001899
reed84984ef2015-07-17 07:09:43 -07001900void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1901 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001902 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001903 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001904}
1905
reede47829b2015-08-06 10:02:53 -07001906void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1907 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001908 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001909 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1910 constraint);
1911}
reede47829b2015-08-06 10:02:53 -07001912
reed4c21dc52015-06-25 12:32:03 -07001913void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1914 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001915 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001916 if (dst.isEmpty()) {
1917 return;
1918 }
1919 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001920 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001921 }
1922 this->onDrawImageNine(image, center, dst, paint);
1923}
1924
reed41af9662015-01-05 07:49:08 -08001925void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001926 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001927 return;
1928 }
reed41af9662015-01-05 07:49:08 -08001929 this->onDrawBitmap(bitmap, dx, dy, paint);
1930}
1931
reede47829b2015-08-06 10:02:53 -07001932void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001933 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001934 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001935 return;
1936 }
reede47829b2015-08-06 10:02:53 -07001937 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001938}
1939
reed84984ef2015-07-17 07:09:43 -07001940void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1941 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001942 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001943}
1944
reede47829b2015-08-06 10:02:53 -07001945void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1946 SrcRectConstraint constraint) {
1947 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1948 constraint);
1949}
reede47829b2015-08-06 10:02:53 -07001950
reed41af9662015-01-05 07:49:08 -08001951void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1952 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001953 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001954 return;
1955 }
reed4c21dc52015-06-25 12:32:03 -07001956 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001957 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001958 }
reed41af9662015-01-05 07:49:08 -08001959 this->onDrawBitmapNine(bitmap, center, dst, paint);
1960}
1961
reed71c3c762015-06-24 10:29:17 -07001962void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1963 const SkColor colors[], int count, SkXfermode::Mode mode,
1964 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001965 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001966 if (count <= 0) {
1967 return;
1968 }
1969 SkASSERT(atlas);
1970 SkASSERT(xform);
1971 SkASSERT(tex);
1972 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1973}
1974
reede47829b2015-08-06 10:02:53 -07001975void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1976 const SkPaint* paint, SrcRectConstraint constraint) {
1977 if (src) {
1978 this->drawImageRect(image, *src, dst, paint, constraint);
1979 } else {
1980 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1981 dst, paint, constraint);
1982 }
1983}
1984void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1985 const SkPaint* paint, SrcRectConstraint constraint) {
1986 if (src) {
1987 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1988 } else {
1989 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1990 dst, paint, constraint);
1991 }
1992}
1993
reed@android.com8a1c16f2008-12-17 15:59:43 +00001994//////////////////////////////////////////////////////////////////////////////
1995// These are the virtual drawing methods
1996//////////////////////////////////////////////////////////////////////////////
1997
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001998void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001999 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002000 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2001 }
2002}
2003
reed41af9662015-01-05 07:49:08 -08002004void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002005 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002006 this->internalDrawPaint(paint);
2007}
2008
2009void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002010 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002011
2012 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002013 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002014 }
2015
reed@google.com4e2b3d32011-04-07 14:18:59 +00002016 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002017}
2018
reed41af9662015-01-05 07:49:08 -08002019void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2020 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002021 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002022 if ((long)count <= 0) {
2023 return;
2024 }
2025
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002026 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002027 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002028 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002029 // special-case 2 points (common for drawing a single line)
2030 if (2 == count) {
2031 r.set(pts[0], pts[1]);
2032 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002033 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002034 }
senorblanco87e066e2015-10-28 11:23:36 -07002035 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2036 return;
2037 }
2038 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002039 }
reed@google.coma584aed2012-05-16 14:06:02 +00002040
halcanary96fcdcc2015-08-27 07:41:13 -07002041 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002042
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002043 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002044
reed@android.com8a1c16f2008-12-17 15:59:43 +00002045 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002046 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002047 }
reed@google.com4b226022011-01-11 18:32:13 +00002048
reed@google.com4e2b3d32011-04-07 14:18:59 +00002049 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002050}
2051
reed41af9662015-01-05 07:49:08 -08002052void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002053 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002054 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002055 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002056 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002057 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2058 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2059 SkRect tmp(r);
2060 tmp.sort();
2061
senorblanco87e066e2015-10-28 11:23:36 -07002062 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2063 return;
2064 }
2065 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002066 }
reed@google.com4b226022011-01-11 18:32:13 +00002067
reedc83a2972015-07-16 07:40:45 -07002068 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002069
2070 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002071 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002072 }
2073
reed@google.com4e2b3d32011-04-07 14:18:59 +00002074 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002075}
2076
reed41af9662015-01-05 07:49:08 -08002077void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002078 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002079 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002080 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002081 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002082 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2083 return;
2084 }
2085 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002086 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002087
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002088 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002089
2090 while (iter.next()) {
2091 iter.fDevice->drawOval(iter, oval, looper.paint());
2092 }
2093
2094 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002095}
2096
reed41af9662015-01-05 07:49:08 -08002097void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002098 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002099 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002100 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002101 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002102 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2103 return;
2104 }
2105 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002106 }
2107
2108 if (rrect.isRect()) {
2109 // call the non-virtual version
2110 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002111 return;
2112 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002113 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002114 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2115 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002116 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002117
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002118 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002119
2120 while (iter.next()) {
2121 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2122 }
2123
2124 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002125}
2126
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002127void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2128 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002129 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002130 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002131 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002132 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2133 return;
2134 }
2135 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002136 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002137
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002138 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002139
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002140 while (iter.next()) {
2141 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2142 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002143
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002144 LOOPER_END
2145}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002146
reed41af9662015-01-05 07:49:08 -08002147void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002148 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002149 if (!path.isFinite()) {
2150 return;
2151 }
2152
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002153 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002154 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002155 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002156 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002157 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2158 return;
2159 }
2160 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002161 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002162
2163 const SkRect& r = path.getBounds();
2164 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002165 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002166 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002167 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002168 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002169 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002170
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002171 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002172
2173 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002174 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002175 }
2176
reed@google.com4e2b3d32011-04-07 14:18:59 +00002177 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002178}
2179
reed262a71b2015-12-05 13:07:27 -08002180bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002181 if (!paint.getImageFilter()) {
2182 return false;
2183 }
2184
2185 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002186 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002187 return false;
2188 }
2189
2190 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2191 // Once we can filter and the filter will return a result larger than itself, we should be
2192 // able to remove this constraint.
2193 // skbug.com/4526
2194 //
2195 SkPoint pt;
2196 ctm.mapXY(x, y, &pt);
2197 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2198 return ir.contains(fMCRec->fRasterClip.getBounds());
2199}
2200
reeda85d4d02015-05-06 12:56:48 -07002201void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002202 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002203 SkRect bounds = SkRect::MakeXYWH(x, y,
2204 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002205 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002206 SkRect tmp = bounds;
2207 if (paint) {
2208 paint->computeFastBounds(tmp, &tmp);
2209 }
2210 if (this->quickReject(tmp)) {
2211 return;
2212 }
reeda85d4d02015-05-06 12:56:48 -07002213 }
2214
2215 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002216 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002217 paint = lazy.init();
2218 }
reed262a71b2015-12-05 13:07:27 -08002219
reed129ed1c2016-02-22 06:42:31 -08002220 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2221 *paint);
2222 if (drawAsSprite && paint->getImageFilter()) {
2223 SkBitmap bitmap;
2224 if (!as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2225 drawAsSprite = false;
2226 } else{
2227 // Until imagefilters are updated, they cannot handle any src type but N32...
2228 if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) {
2229 drawAsSprite = false;
2230 }
2231 }
2232 }
2233
reed262a71b2015-12-05 13:07:27 -08002234 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2235
reeda85d4d02015-05-06 12:56:48 -07002236 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002237 const SkPaint& pnt = looper.paint();
2238 if (drawAsSprite && pnt.getImageFilter()) {
2239 SkBitmap bitmap;
2240 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2241 SkPoint pt;
2242 iter.fMatrix->mapXY(x, y, &pt);
2243 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2244 SkScalarRoundToInt(pt.fX),
2245 SkScalarRoundToInt(pt.fY), pnt);
2246 }
2247 } else {
2248 iter.fDevice->drawImage(iter, image, x, y, pnt);
2249 }
reeda85d4d02015-05-06 12:56:48 -07002250 }
2251
2252 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002253}
2254
reed41af9662015-01-05 07:49:08 -08002255void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002256 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002257 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002258 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002259 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002260 if (paint) {
2261 paint->computeFastBounds(dst, &storage);
2262 }
2263 if (this->quickReject(storage)) {
2264 return;
2265 }
reeda85d4d02015-05-06 12:56:48 -07002266 }
2267 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002268 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002269 paint = lazy.init();
2270 }
2271
senorblancoc41e7e12015-12-07 12:51:30 -08002272 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002273 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002274
2275 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002276 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002277 }
2278
2279 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002280}
2281
reed41af9662015-01-05 07:49:08 -08002282void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002283 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002284 SkDEBUGCODE(bitmap.validate();)
2285
reed33366972015-10-08 09:22:02 -07002286 if (bitmap.drawsNothing()) {
2287 return;
2288 }
2289
2290 SkLazyPaint lazy;
2291 if (nullptr == paint) {
2292 paint = lazy.init();
2293 }
2294
2295 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2296
2297 SkRect storage;
2298 const SkRect* bounds = nullptr;
2299 if (paint->canComputeFastBounds()) {
2300 bitmap.getBounds(&storage);
2301 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002302 SkRect tmp = storage;
2303 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2304 return;
2305 }
2306 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 }
reed@google.com4b226022011-01-11 18:32:13 +00002308
reed129ed1c2016-02-22 06:42:31 -08002309 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2310 *paint);
2311 if (drawAsSprite && paint->getImageFilter()) {
2312 // Until imagefilters are updated, they cannot handle any src type but N32...
2313 if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) {
2314 drawAsSprite = false;
2315 }
2316 }
2317
reed262a71b2015-12-05 13:07:27 -08002318 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002319
2320 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002321 const SkPaint& pnt = looper.paint();
2322 if (drawAsSprite && pnt.getImageFilter()) {
2323 SkPoint pt;
2324 iter.fMatrix->mapXY(x, y, &pt);
2325 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2326 SkScalarRoundToInt(pt.fX),
2327 SkScalarRoundToInt(pt.fY), pnt);
2328 } else {
2329 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2330 }
reed33366972015-10-08 09:22:02 -07002331 }
reed262a71b2015-12-05 13:07:27 -08002332
reed33366972015-10-08 09:22:02 -07002333 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002334}
2335
reed@google.com9987ec32011-09-07 11:57:52 +00002336// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002337void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002338 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002339 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002340 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002341 return;
2342 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002343
halcanary96fcdcc2015-08-27 07:41:13 -07002344 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002345 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002346 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2347 return;
2348 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002349 }
reed@google.com3d608122011-11-21 15:16:16 +00002350
reed@google.com33535f32012-09-25 15:37:50 +00002351 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002352 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002353 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002354 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002355
senorblancoc41e7e12015-12-07 12:51:30 -08002356 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002357 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002358
reed@google.com33535f32012-09-25 15:37:50 +00002359 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002360 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002361 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002362
reed@google.com33535f32012-09-25 15:37:50 +00002363 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364}
2365
reed41af9662015-01-05 07:49:08 -08002366void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002367 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002368 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002369 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002370 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002371}
2372
reed4c21dc52015-06-25 12:32:03 -07002373void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2374 const SkPaint* paint) {
2375 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2376
halcanary96fcdcc2015-08-27 07:41:13 -07002377 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002378 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002379 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2380 return;
2381 }
reed@google.com3d608122011-11-21 15:16:16 +00002382 }
reed4c21dc52015-06-25 12:32:03 -07002383
2384 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002385 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002386 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002387 }
reed4c21dc52015-06-25 12:32:03 -07002388
senorblancoc41e7e12015-12-07 12:51:30 -08002389 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002390
2391 while (iter.next()) {
2392 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002393 }
reed4c21dc52015-06-25 12:32:03 -07002394
2395 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002396}
2397
reed41af9662015-01-05 07:49:08 -08002398void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2399 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002400 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002401 SkDEBUGCODE(bitmap.validate();)
2402
halcanary96fcdcc2015-08-27 07:41:13 -07002403 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002404 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002405 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2406 return;
2407 }
reed4c21dc52015-06-25 12:32:03 -07002408 }
2409
2410 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002411 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002412 paint = lazy.init();
2413 }
2414
senorblancoc41e7e12015-12-07 12:51:30 -08002415 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002416
2417 while (iter.next()) {
2418 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2419 }
2420
2421 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002422}
2423
reed@google.comf67e4cf2011-03-15 20:56:58 +00002424class SkDeviceFilteredPaint {
2425public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002426 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002427 uint32_t filteredFlags = device->filterTextFlags(paint);
2428 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002429 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002430 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002431 fPaint = newPaint;
2432 } else {
2433 fPaint = &paint;
2434 }
2435 }
2436
reed@google.comf67e4cf2011-03-15 20:56:58 +00002437 const SkPaint& paint() const { return *fPaint; }
2438
2439private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002440 const SkPaint* fPaint;
2441 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002442};
2443
bungeman@google.com52c748b2011-08-22 21:30:43 +00002444void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2445 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002446 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002447 draw.fDevice->drawRect(draw, r, paint);
2448 } else {
2449 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002450 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002451 draw.fDevice->drawRect(draw, r, p);
2452 }
2453}
2454
2455void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2456 const char text[], size_t byteLength,
2457 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002458 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002459
2460 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002461 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002462 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002463 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002464 return;
2465 }
2466
2467 SkScalar width = 0;
2468 SkPoint start;
2469
2470 start.set(0, 0); // to avoid warning
2471 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2472 SkPaint::kStrikeThruText_Flag)) {
2473 width = paint.measureText(text, byteLength);
2474
2475 SkScalar offsetX = 0;
2476 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2477 offsetX = SkScalarHalf(width);
2478 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2479 offsetX = width;
2480 }
2481 start.set(x - offsetX, y);
2482 }
2483
2484 if (0 == width) {
2485 return;
2486 }
2487
2488 uint32_t flags = paint.getFlags();
2489
2490 if (flags & (SkPaint::kUnderlineText_Flag |
2491 SkPaint::kStrikeThruText_Flag)) {
2492 SkScalar textSize = paint.getTextSize();
2493 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2494 SkRect r;
2495
2496 r.fLeft = start.fX;
2497 r.fRight = start.fX + width;
2498
2499 if (flags & SkPaint::kUnderlineText_Flag) {
2500 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2501 start.fY);
2502 r.fTop = offset;
2503 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002504 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002505 }
2506 if (flags & SkPaint::kStrikeThruText_Flag) {
2507 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2508 start.fY);
2509 r.fTop = offset;
2510 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002511 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002512 }
2513 }
2514}
2515
reed@google.come0d9ce82014-04-23 04:00:17 +00002516void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2517 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002518 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002519
2520 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002521 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002522 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002523 DrawTextDecorations(iter, dfp.paint(),
2524 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002525 }
2526
reed@google.com4e2b3d32011-04-07 14:18:59 +00002527 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002528}
2529
reed@google.come0d9ce82014-04-23 04:00:17 +00002530void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2531 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002532 SkPoint textOffset = SkPoint::Make(0, 0);
2533
halcanary96fcdcc2015-08-27 07:41:13 -07002534 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002535
reed@android.com8a1c16f2008-12-17 15:59:43 +00002536 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002537 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002538 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002539 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002540 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002541
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::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2546 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002547
2548 SkPoint textOffset = SkPoint::Make(0, constY);
2549
halcanary96fcdcc2015-08-27 07:41:13 -07002550 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002551
reed@android.com8a1c16f2008-12-17 15:59:43 +00002552 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002553 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002554 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002555 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002556 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002557
reed@google.com4e2b3d32011-04-07 14:18:59 +00002558 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002559}
2560
reed@google.come0d9ce82014-04-23 04:00:17 +00002561void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2562 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002563 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002564
reed@android.com8a1c16f2008-12-17 15:59:43 +00002565 while (iter.next()) {
2566 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002567 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002568 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002569
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002570 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002571}
2572
fmalita00d5c2c2014-08-21 08:53:26 -07002573void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2574 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002575
fmalita85d5eb92015-03-04 11:20:12 -08002576 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002577 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002578 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002579 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002580 SkRect tmp;
2581 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2582 return;
2583 }
2584 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002585 }
2586
fmalita024f9962015-03-03 19:08:17 -08002587 // We cannot filter in the looper as we normally do, because the paint is
2588 // incomplete at this point (text-related attributes are embedded within blob run paints).
2589 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002590 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002591
fmalita85d5eb92015-03-04 11:20:12 -08002592 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002593
fmalitaaa1b9122014-08-28 14:32:24 -07002594 while (iter.next()) {
2595 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002596 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002597 }
2598
fmalitaaa1b9122014-08-28 14:32:24 -07002599 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002600
2601 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002602}
2603
reed@google.come0d9ce82014-04-23 04:00:17 +00002604// These will become non-virtual, so they always call the (virtual) onDraw... method
2605void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2606 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002607 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002608 this->onDrawText(text, byteLength, x, y, paint);
2609}
2610void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2611 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002612 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002613 this->onDrawPosText(text, byteLength, pos, paint);
2614}
2615void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2616 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002617 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002618 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2619}
2620void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2621 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002622 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002623 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2624}
fmalita00d5c2c2014-08-21 08:53:26 -07002625void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2626 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002627 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002628 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002629 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002630}
reed@google.come0d9ce82014-04-23 04:00:17 +00002631
reed41af9662015-01-05 07:49:08 -08002632void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2633 const SkPoint verts[], const SkPoint texs[],
2634 const SkColor colors[], SkXfermode* xmode,
2635 const uint16_t indices[], int indexCount,
2636 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002637 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002638 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002639
reed@android.com8a1c16f2008-12-17 15:59:43 +00002640 while (iter.next()) {
2641 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002642 colors, xmode, indices, indexCount,
2643 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002644 }
reed@google.com4b226022011-01-11 18:32:13 +00002645
reed@google.com4e2b3d32011-04-07 14:18:59 +00002646 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002647}
2648
dandovb3c9d1c2014-08-12 08:34:29 -07002649void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2650 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002651 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002652 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002653 return;
2654 }
mtklein6cfa73a2014-08-13 13:33:49 -07002655
dandovecfff212014-08-04 10:02:00 -07002656 // Since a patch is always within the convex hull of the control points, we discard it when its
2657 // bounding rectangle is completely outside the current clip.
2658 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002659 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002660 if (this->quickReject(bounds)) {
2661 return;
2662 }
mtklein6cfa73a2014-08-13 13:33:49 -07002663
dandovb3c9d1c2014-08-12 08:34:29 -07002664 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2665}
2666
2667void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2668 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2669
halcanary96fcdcc2015-08-27 07:41:13 -07002670 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002671
dandovecfff212014-08-04 10:02:00 -07002672 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002673 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002674 }
mtklein6cfa73a2014-08-13 13:33:49 -07002675
dandovecfff212014-08-04 10:02:00 -07002676 LOOPER_END
2677}
2678
reeda8db7282015-07-07 10:22:31 -07002679void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002680 RETURN_ON_NULL(dr);
2681 if (x || y) {
2682 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2683 this->onDrawDrawable(dr, &matrix);
2684 } else {
2685 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002686 }
2687}
2688
reeda8db7282015-07-07 10:22:31 -07002689void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002690 RETURN_ON_NULL(dr);
2691 if (matrix && matrix->isIdentity()) {
2692 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002693 }
reede3b38ce2016-01-08 09:18:44 -08002694 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002695}
2696
2697void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2698 SkRect bounds = dr->getBounds();
2699 if (matrix) {
2700 matrix->mapRect(&bounds);
2701 }
2702 if (this->quickReject(bounds)) {
2703 return;
2704 }
2705 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002706}
2707
reed71c3c762015-06-24 10:29:17 -07002708void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2709 const SkColor colors[], int count, SkXfermode::Mode mode,
2710 const SkRect* cull, const SkPaint* paint) {
2711 if (cull && this->quickReject(*cull)) {
2712 return;
2713 }
2714
2715 SkPaint pnt;
2716 if (paint) {
2717 pnt = *paint;
2718 }
2719
halcanary96fcdcc2015-08-27 07:41:13 -07002720 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002721 while (iter.next()) {
2722 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2723 }
2724 LOOPER_END
2725}
2726
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727//////////////////////////////////////////////////////////////////////////////
2728// These methods are NOT virtual, and therefore must call back into virtual
2729// methods, rather than actually drawing themselves.
2730//////////////////////////////////////////////////////////////////////////////
2731
2732void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002733 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002734 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 SkPaint paint;
2736
2737 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002738 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002739 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740 }
2741 this->drawPaint(paint);
2742}
2743
reed@android.com845fdac2009-06-23 03:01:32 +00002744void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002745 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002746 SkPaint paint;
2747
2748 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002749 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002750 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 }
2752 this->drawPaint(paint);
2753}
2754
2755void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002756 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002757 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002758
reed@android.com8a1c16f2008-12-17 15:59:43 +00002759 pt.set(x, y);
2760 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2761}
2762
2763void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002764 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002765 SkPoint pt;
2766 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002767
reed@android.com8a1c16f2008-12-17 15:59:43 +00002768 pt.set(x, y);
2769 paint.setColor(color);
2770 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2771}
2772
2773void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2774 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002775 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002777
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778 pts[0].set(x0, y0);
2779 pts[1].set(x1, y1);
2780 this->drawPoints(kLines_PointMode, 2, pts, paint);
2781}
2782
2783void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2784 SkScalar right, SkScalar bottom,
2785 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002786 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002787 SkRect r;
2788
2789 r.set(left, top, right, bottom);
2790 this->drawRect(r, paint);
2791}
2792
2793void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2794 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002795 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796 if (radius < 0) {
2797 radius = 0;
2798 }
2799
2800 SkRect r;
2801 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002802 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002803}
2804
2805void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2806 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002807 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002808 if (rx > 0 && ry > 0) {
2809 if (paint.canComputeFastBounds()) {
2810 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002811 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812 return;
2813 }
2814 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002815 SkRRect rrect;
2816 rrect.setRectXY(r, rx, ry);
2817 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002818 } else {
2819 this->drawRect(r, paint);
2820 }
2821}
2822
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2824 SkScalar sweepAngle, bool useCenter,
2825 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002826 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002827 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2828 this->drawOval(oval, paint);
2829 } else {
2830 SkPath path;
2831 if (useCenter) {
2832 path.moveTo(oval.centerX(), oval.centerY());
2833 }
2834 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2835 if (useCenter) {
2836 path.close();
2837 }
2838 this->drawPath(path, paint);
2839 }
2840}
2841
2842void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2843 const SkPath& path, SkScalar hOffset,
2844 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002845 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002846 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002847
reed@android.com8a1c16f2008-12-17 15:59:43 +00002848 matrix.setTranslate(hOffset, vOffset);
2849 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2850}
2851
reed@android.comf76bacf2009-05-13 14:00:33 +00002852///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002853
2854/**
2855 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2856 * against the playback cost of recursing into the subpicture to get at its actual ops.
2857 *
2858 * For now we pick a conservatively small value, though measurement (and other heuristics like
2859 * the type of ops contained) may justify changing this value.
2860 */
2861#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002862
reedd5fa1a42014-08-09 11:08:05 -07002863void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002864 RETURN_ON_NULL(picture);
2865
reed1c2c4412015-04-30 13:09:24 -07002866 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002867 if (matrix && matrix->isIdentity()) {
2868 matrix = nullptr;
2869 }
2870 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2871 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2872 picture->playback(this);
2873 } else {
2874 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002875 }
2876}
robertphillips9b14f262014-06-04 05:40:44 -07002877
reedd5fa1a42014-08-09 11:08:05 -07002878void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2879 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002880 if (!paint || paint->canComputeFastBounds()) {
2881 SkRect bounds = picture->cullRect();
2882 if (paint) {
2883 paint->computeFastBounds(bounds, &bounds);
2884 }
2885 if (matrix) {
2886 matrix->mapRect(&bounds);
2887 }
2888 if (this->quickReject(bounds)) {
2889 return;
2890 }
2891 }
2892
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002893 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002894 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002895 // Canvas has to first give the device the opportunity to render
2896 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002897 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002898 return; // the device has rendered the entire picture
2899 }
2900 }
2901
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002902 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002903 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002904}
2905
reed@android.com8a1c16f2008-12-17 15:59:43 +00002906///////////////////////////////////////////////////////////////////////////////
2907///////////////////////////////////////////////////////////////////////////////
2908
2909SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002910 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002911
2912 SkASSERT(canvas);
2913
2914 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2915 fDone = !fImpl->next();
2916}
2917
2918SkCanvas::LayerIter::~LayerIter() {
2919 fImpl->~SkDrawIter();
2920}
2921
2922void SkCanvas::LayerIter::next() {
2923 fDone = !fImpl->next();
2924}
2925
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002926SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002927 return fImpl->getDevice();
2928}
2929
2930const SkMatrix& SkCanvas::LayerIter::matrix() const {
2931 return fImpl->getMatrix();
2932}
2933
2934const SkPaint& SkCanvas::LayerIter::paint() const {
2935 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002936 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002937 paint = &fDefaultPaint;
2938 }
2939 return *paint;
2940}
2941
2942const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2943int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2944int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002945
2946///////////////////////////////////////////////////////////////////////////////
2947
fmalitac3b589a2014-06-05 12:40:07 -07002948SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002949
2950///////////////////////////////////////////////////////////////////////////////
2951
2952static bool supported_for_raster_canvas(const SkImageInfo& info) {
2953 switch (info.alphaType()) {
2954 case kPremul_SkAlphaType:
2955 case kOpaque_SkAlphaType:
2956 break;
2957 default:
2958 return false;
2959 }
2960
2961 switch (info.colorType()) {
2962 case kAlpha_8_SkColorType:
2963 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002964 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002965 break;
2966 default:
2967 return false;
2968 }
2969
2970 return true;
2971}
2972
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002973SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2974 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002975 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002976 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002977
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002978 SkBitmap bitmap;
2979 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002980 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002981 }
halcanary385fe4d2015-08-26 13:07:48 -07002982 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002983}
reedd5fa1a42014-08-09 11:08:05 -07002984
2985///////////////////////////////////////////////////////////////////////////////
2986
2987SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002988 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002989 : fCanvas(canvas)
2990 , fSaveCount(canvas->getSaveCount())
2991{
bsalomon49f085d2014-09-05 13:34:00 -07002992 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002993 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002994 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002995 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002996 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002997 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002998 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002999 canvas->save();
3000 }
mtklein6cfa73a2014-08-13 13:33:49 -07003001
bsalomon49f085d2014-09-05 13:34:00 -07003002 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003003 canvas->concat(*matrix);
3004 }
3005}
3006
3007SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3008 fCanvas->restoreToCount(fSaveCount);
3009}