blob: c8c4b8749b9b748d7f84127f7e983f63b22f35a0 [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) {
reed96e657d2015-03-10 17:30:07 -07001079 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
reed4960eee2015-12-18 07:09:18 -08001170void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1171 const SkRect* bounds = rec.fBounds;
1172 const SkPaint* paint = rec.fPaint;
1173 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1174
reed@google.comb93ba452014-03-10 19:47:58 +00001175#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001176 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001177#endif
1178
junov@chromium.orga907ac32012-02-24 21:54:07 +00001179 // do this before we create the layer. We don't call the public save() since
1180 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001181 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001182
1183 fDeviceCMDirty = true;
1184
1185 SkIRect ir;
reed4960eee2015-12-18 07:09:18 -08001186 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001187 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188 }
1189
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001190 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1191 // the clipRectBounds() call above?
1192 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001193 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001194 }
1195
reed4960eee2015-12-18 07:09:18 -08001196 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001197 SkPixelGeometry geo = fProps.pixelGeometry();
1198 if (paint) {
reed76033be2015-03-14 10:54:31 -07001199 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001200 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001201 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001202 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001203 }
1204 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001205 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1206 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001207
reedb2db8982014-11-13 12:41:02 -08001208 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001209 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001210 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001211 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001212 }
reedb2db8982014-11-13 12:41:02 -08001213
reed61f501f2015-04-29 08:34:00 -07001214 bool forceSpriteOnRestore = false;
1215 {
reed70ee31b2015-12-10 13:44:45 -08001216 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001217 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001218 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001219 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1220 preserveLCDText, false);
reed61f501f2015-04-29 08:34:00 -07001221 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001222 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001223 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001224 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1225 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001226 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001227 SkErrorInternals::SetError(kInternalError_SkError,
1228 "Unable to create device for layer.");
1229 return;
1230 }
1231 forceSpriteOnRestore = true;
1232 }
1233 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001234 }
reed@google.com6f8f2922011-03-04 22:27:10 +00001235 device->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001236
reedbfd5f172016-01-07 11:28:08 -08001237 if (rec.fBackdrop) {
1238 draw_filter_into_device(fMCRec->fTopLayer->fDevice, rec.fBackdrop, device, fMCRec->fMatrix);
robertphillips7354a4b2015-12-16 05:08:27 -08001239 }
1240
halcanary385fe4d2015-08-26 13:07:48 -07001241 DeviceCM* layer =
1242 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243 device->unref();
1244
1245 layer->fNext = fMCRec->fTopLayer;
1246 fMCRec->fLayer = layer;
1247 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001248}
1249
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001250int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001251 if (0xFF == alpha) {
1252 return this->saveLayer(bounds, nullptr);
1253 } else {
1254 SkPaint tmpPaint;
1255 tmpPaint.setAlpha(alpha);
1256 return this->saveLayer(bounds, &tmpPaint);
1257 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001258}
1259
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260void SkCanvas::internalRestore() {
1261 SkASSERT(fMCStack.count() != 0);
1262
1263 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001264 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265
reed687fa1c2015-04-07 08:00:56 -07001266 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001267
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001268 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001269 DeviceCM* layer = fMCRec->fLayer; // may be null
1270 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001271 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272
1273 // now do the normal restore()
1274 fMCRec->~MCRec(); // balanced in save()
1275 fMCStack.pop_back();
1276 fMCRec = (MCRec*)fMCStack.back();
1277
1278 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1279 since if we're being recorded, we don't want to record this (the
1280 recorder will have already recorded the restore).
1281 */
bsalomon49f085d2014-09-05 13:34:00 -07001282 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001284 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001285 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001286 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001287 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001289 delete layer;
reedb679ca82015-04-07 04:40:48 -07001290 } else {
1291 // we're at the root
reeda499f902015-05-01 09:34:31 -07001292 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001293 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001295 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296}
1297
reed4a8126e2014-09-22 07:29:03 -07001298SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001299 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001300 props = &fProps;
1301 }
1302 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001303}
1304
reed4a8126e2014-09-22 07:29:03 -07001305SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001306 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001307 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001308}
1309
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001310SkImageInfo SkCanvas::imageInfo() const {
1311 SkBaseDevice* dev = this->getDevice();
1312 if (dev) {
1313 return dev->imageInfo();
1314 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001315 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001316 }
1317}
1318
1319const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001320 SkPixmap pmap;
1321 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001322 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001323 }
1324 if (info) {
1325 *info = pmap.info();
1326 }
1327 if (rowBytes) {
1328 *rowBytes = pmap.rowBytes();
1329 }
1330 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001331}
1332
reed884e97c2015-05-26 11:31:54 -07001333bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001334 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001335 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001336}
1337
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001338void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001339 SkPixmap pmap;
1340 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001341 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001342 }
1343 if (info) {
1344 *info = pmap.info();
1345 }
1346 if (rowBytes) {
1347 *rowBytes = pmap.rowBytes();
1348 }
1349 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001350 *origin = this->getTopDevice(false)->getOrigin();
1351 }
reed884e97c2015-05-26 11:31:54 -07001352 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001353}
1354
reed884e97c2015-05-26 11:31:54 -07001355bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001356 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001357 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001358}
1359
reed@android.com8a1c16f2008-12-17 15:59:43 +00001360/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001361
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001362void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001363 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001364 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001365 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366 paint = &tmp;
1367 }
reed@google.com4b226022011-01-11 18:32:13 +00001368
reed@google.com8926b162012-03-23 15:36:36 +00001369 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001370 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001371 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001372 paint = &looper.paint();
1373 SkImageFilter* filter = paint->getImageFilter();
1374 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001375 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001376 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001377 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001378 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001379 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001380 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001381 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblancodb64af32015-12-09 10:11:43 -08001382 SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
senorblancobe129b22014-08-08 07:14:35 -07001383 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reed4e23cda2016-01-11 10:56:59 -08001384 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001385 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001386 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001387 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001388 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1389 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001390 }
reed61f501f2015-04-29 08:34:00 -07001391 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001392 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001393 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001394 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001395 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001396 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001397 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001398 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001399}
1400
reed32704672015-12-16 08:27:10 -08001401/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001402
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001403void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001404 SkMatrix m;
1405 m.setTranslate(dx, dy);
1406 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407}
1408
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001409void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001410 SkMatrix m;
1411 m.setScale(sx, sy);
1412 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413}
1414
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001415void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001416 SkMatrix m;
1417 m.setRotate(degrees);
1418 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419}
1420
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001421void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001422 SkMatrix m;
1423 m.setSkew(sx, sy);
1424 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001425}
1426
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001427void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001428 if (matrix.isIdentity()) {
1429 return;
1430 }
1431
reed2ff1fce2014-12-11 07:07:37 -08001432 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001434 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001435 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001436
1437 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001438}
1439
reed86a17e72015-05-14 12:25:22 -07001440void SkCanvas::setMatrix(const SkMatrix& matrix) {
1441 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001443 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001444 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001445 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001446}
1447
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448void SkCanvas::resetMatrix() {
1449 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001450
reed@android.com8a1c16f2008-12-17 15:59:43 +00001451 matrix.reset();
1452 this->setMatrix(matrix);
1453}
1454
1455//////////////////////////////////////////////////////////////////////////////
1456
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001457void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001458 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001459 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1460 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001461}
1462
1463void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001464#ifdef SK_ENABLE_CLIP_QUICKREJECT
1465 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001466 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001467 return false;
1468 }
1469
reed@google.com3b3e8952012-08-16 20:53:31 +00001470 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001471 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001472 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001473
reed687fa1c2015-04-07 08:00:56 -07001474 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001475 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001476 }
1477 }
1478#endif
1479
bsalomonac8cabd2015-11-20 18:53:07 -08001480 if (!fAllowSoftClip) {
1481 edgeStyle = kHard_ClipEdgeStyle;
1482 }
reed90ba0952015-11-20 13:42:47 -08001483
reedc64eff52015-11-21 12:39:45 -08001484 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1485 SkRect devR;
1486 if (rectStaysRect) {
1487 fMCRec->fMatrix.mapRect(&devR, rect);
1488 }
bsalomonac8cabd2015-11-20 18:53:07 -08001489
reedc64eff52015-11-21 12:39:45 -08001490 // Check if we can quick-accept the clip call (and do nothing)
1491 //
1492 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1493 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1494 // might allow lazy save/restores to eliminate entire save/restore blocks.
1495 //
1496 if (SkRegion::kIntersect_Op == op &&
1497 kHard_ClipEdgeStyle == edgeStyle
1498 && rectStaysRect)
1499 {
1500 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1501#if 0
1502 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1503 rect.left(), rect.top(), rect.right(), rect.bottom());
1504#endif
1505 return;
1506 }
1507 }
1508
1509 AutoValidateClip avc(this);
1510
1511 fDeviceCMDirty = true;
1512 fCachedLocalClipBoundsDirty = true;
1513
1514 if (rectStaysRect) {
1515 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1516 fClipStack->clipDevRect(devR, op, isAA);
senorblancoafc7cce2016-02-02 18:44:15 -08001517 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001518 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001519 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001520 // and clip against that, since it can handle any matrix. However, to
1521 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1522 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001523 SkPath path;
1524
1525 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001526 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001527 }
1528}
1529
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001530void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001531 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001532 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001533 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001534 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1535 } else {
1536 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001537 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001538}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001539
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001540void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001541 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001542 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001543 AutoValidateClip avc(this);
1544
1545 fDeviceCMDirty = true;
1546 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001547 if (!fAllowSoftClip) {
1548 edgeStyle = kHard_ClipEdgeStyle;
1549 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001550
reed687fa1c2015-04-07 08:00:56 -07001551 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001552
senorblancoafc7cce2016-02-02 18:44:15 -08001553 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
robertphillips125f19a2015-11-23 09:00:05 -08001554 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001555 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001556 }
1557
1558 SkPath path;
1559 path.addRRect(rrect);
1560 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001561 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001562}
1563
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001564void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001565 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001566 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001567
1568 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1569 SkRect r;
1570 if (path.isRect(&r)) {
1571 this->onClipRect(r, op, edgeStyle);
1572 return;
1573 }
1574 SkRRect rrect;
1575 if (path.isOval(&r)) {
1576 rrect.setOval(r);
1577 this->onClipRRect(rrect, op, edgeStyle);
1578 return;
1579 }
1580 if (path.isRRect(&rrect)) {
1581 this->onClipRRect(rrect, op, edgeStyle);
1582 return;
1583 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001584 }
robertphillips39f05382015-11-24 09:30:12 -08001585
1586 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001587}
1588
1589void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001590#ifdef SK_ENABLE_CLIP_QUICKREJECT
1591 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001592 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001593 return false;
1594 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001595
reed@google.com3b3e8952012-08-16 20:53:31 +00001596 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001597 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001598 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001599
reed687fa1c2015-04-07 08:00:56 -07001600 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001601 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001602 }
1603 }
1604#endif
1605
reed@google.com5c3d1472011-02-22 19:12:23 +00001606 AutoValidateClip avc(this);
1607
reed@android.com8a1c16f2008-12-17 15:59:43 +00001608 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001609 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001610 if (!fAllowSoftClip) {
1611 edgeStyle = kHard_ClipEdgeStyle;
1612 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001613
1614 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001615 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001616
reed@google.comfe701122011-11-08 19:41:23 +00001617 // Check if the transfomation, or the original path itself
1618 // made us empty. Note this can also happen if we contained NaN
1619 // values. computing the bounds detects this, and will set our
1620 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1621 if (devPath.getBounds().isEmpty()) {
1622 // resetting the path will remove any NaN or other wanky values
1623 // that might upset our scan converter.
1624 devPath.reset();
1625 }
1626
reed@google.com5c3d1472011-02-22 19:12:23 +00001627 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001628 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001629
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001630 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001631 bool clipIsAA = getClipStack()->asPath(&devPath);
1632 if (clipIsAA) {
1633 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001634 }
fmalita1a481fe2015-02-04 07:39:34 -08001635
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001636 op = SkRegion::kReplace_Op;
1637 }
1638
senorblancoafc7cce2016-02-02 18:44:15 -08001639 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001640}
1641
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001642void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001643 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001644 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001645}
1646
1647void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001648 AutoValidateClip avc(this);
1649
reed@android.com8a1c16f2008-12-17 15:59:43 +00001650 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001651 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652
reed@google.com5c3d1472011-02-22 19:12:23 +00001653 // todo: signal fClipStack that we have a region, and therefore (I guess)
1654 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001655 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001656
reed1f836ee2014-07-07 07:49:34 -07001657 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658}
1659
reed@google.com819c9212011-02-23 18:56:55 +00001660#ifdef SK_DEBUG
1661void SkCanvas::validateClip() const {
1662 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001663 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001664 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001665 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001666 return;
1667 }
1668
reed@google.com819c9212011-02-23 18:56:55 +00001669 SkIRect ir;
1670 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001671 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001672
reed687fa1c2015-04-07 08:00:56 -07001673 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001674 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001675 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001676 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001677 case SkClipStack::Element::kRect_Type:
1678 element->getRect().round(&ir);
1679 tmpClip.op(ir, element->getOp());
1680 break;
1681 case SkClipStack::Element::kEmpty_Type:
1682 tmpClip.setEmpty();
1683 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001684 default: {
1685 SkPath path;
1686 element->asPath(&path);
senorblancoafc7cce2016-02-02 18:44:15 -08001687 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001688 break;
1689 }
reed@google.com819c9212011-02-23 18:56:55 +00001690 }
1691 }
reed@google.com819c9212011-02-23 18:56:55 +00001692}
1693#endif
1694
reed@google.com90c07ea2012-04-13 13:50:27 +00001695void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001696 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001697 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001698
halcanary96fcdcc2015-08-27 07:41:13 -07001699 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001700 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001701 }
1702}
1703
reed@google.com5c3d1472011-02-22 19:12:23 +00001704///////////////////////////////////////////////////////////////////////////////
1705
reed@google.com754de5f2014-02-24 19:38:20 +00001706bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001707 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001708}
1709
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001710bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001711 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001712}
1713
reed@google.com3b3e8952012-08-16 20:53:31 +00001714bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001715 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001716 return true;
1717
reed1f836ee2014-07-07 07:49:34 -07001718 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001719 return true;
1720 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001721
reed1f836ee2014-07-07 07:49:34 -07001722 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001723 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001724 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001725 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001726 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001727 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001728
reed@android.coma380ae42009-07-21 01:17:02 +00001729 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001730 // TODO: should we use | instead, or compare all 4 at once?
1731 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001732 return true;
1733 }
reed@google.comc0784db2013-12-13 21:16:12 +00001734 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001735 return true;
1736 }
1737 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001738 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739}
1740
reed@google.com3b3e8952012-08-16 20:53:31 +00001741bool SkCanvas::quickReject(const SkPath& path) const {
1742 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001743}
1744
reed@google.com3b3e8952012-08-16 20:53:31 +00001745bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001746 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001747 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001748 return false;
1749 }
1750
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001751 SkMatrix inverse;
1752 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001753 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001754 if (bounds) {
1755 bounds->setEmpty();
1756 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001757 return false;
1758 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001759
bsalomon49f085d2014-09-05 13:34:00 -07001760 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001761 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001762 // adjust it outwards in case we are antialiasing
1763 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001764
reed@google.com8f4d2302013-12-17 16:44:46 +00001765 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1766 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001767 inverse.mapRect(bounds, r);
1768 }
1769 return true;
1770}
1771
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001772bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001773 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001774 if (clip.isEmpty()) {
1775 if (bounds) {
1776 bounds->setEmpty();
1777 }
1778 return false;
1779 }
1780
bsalomon49f085d2014-09-05 13:34:00 -07001781 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001782 *bounds = clip.getBounds();
1783 }
1784 return true;
1785}
1786
reed@android.com8a1c16f2008-12-17 15:59:43 +00001787const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001788 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001789}
1790
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001791const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001792 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001793}
1794
reed@google.com9c135db2014-03-12 18:28:35 +00001795GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1796 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001797 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001798}
1799
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001800GrContext* SkCanvas::getGrContext() {
1801#if SK_SUPPORT_GPU
1802 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001803 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001804 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001805 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001806 return renderTarget->getContext();
1807 }
1808 }
1809#endif
1810
halcanary96fcdcc2015-08-27 07:41:13 -07001811 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001812
1813}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001814
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001815void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1816 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001817 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001818 if (outer.isEmpty()) {
1819 return;
1820 }
1821 if (inner.isEmpty()) {
1822 this->drawRRect(outer, paint);
1823 return;
1824 }
1825
1826 // We don't have this method (yet), but technically this is what we should
1827 // be able to assert...
1828 // SkASSERT(outer.contains(inner));
1829 //
1830 // For now at least check for containment of bounds
1831 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1832
1833 this->onDrawDRRect(outer, inner, paint);
1834}
1835
reed41af9662015-01-05 07:49:08 -08001836// These need to stop being virtual -- clients need to override the onDraw... versions
1837
1838void SkCanvas::drawPaint(const SkPaint& paint) {
1839 this->onDrawPaint(paint);
1840}
1841
1842void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1843 this->onDrawRect(r, paint);
1844}
1845
1846void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1847 this->onDrawOval(r, paint);
1848}
1849
1850void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1851 this->onDrawRRect(rrect, paint);
1852}
1853
1854void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1855 this->onDrawPoints(mode, count, pts, paint);
1856}
1857
1858void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1859 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1860 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1861 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1862 indices, indexCount, paint);
1863}
1864
1865void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1866 this->onDrawPath(path, paint);
1867}
1868
reeda85d4d02015-05-06 12:56:48 -07001869void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001870 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001871 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001872}
1873
reede47829b2015-08-06 10:02:53 -07001874void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1875 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001876 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001877 if (dst.isEmpty() || src.isEmpty()) {
1878 return;
1879 }
1880 this->onDrawImageRect(image, &src, dst, paint, constraint);
1881}
reed41af9662015-01-05 07:49:08 -08001882
reed84984ef2015-07-17 07:09:43 -07001883void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1884 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001885 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001886 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001887}
1888
reede47829b2015-08-06 10:02:53 -07001889void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1890 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001891 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001892 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1893 constraint);
1894}
reede47829b2015-08-06 10:02:53 -07001895
reed4c21dc52015-06-25 12:32:03 -07001896void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1897 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001898 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001899 if (dst.isEmpty()) {
1900 return;
1901 }
1902 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001903 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001904 }
1905 this->onDrawImageNine(image, center, dst, paint);
1906}
1907
reed41af9662015-01-05 07:49:08 -08001908void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001909 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001910 return;
1911 }
reed41af9662015-01-05 07:49:08 -08001912 this->onDrawBitmap(bitmap, dx, dy, paint);
1913}
1914
reede47829b2015-08-06 10:02:53 -07001915void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001916 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001917 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001918 return;
1919 }
reede47829b2015-08-06 10:02:53 -07001920 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001921}
1922
reed84984ef2015-07-17 07:09:43 -07001923void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1924 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001925 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001926}
1927
reede47829b2015-08-06 10:02:53 -07001928void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1929 SrcRectConstraint constraint) {
1930 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1931 constraint);
1932}
reede47829b2015-08-06 10:02:53 -07001933
reed41af9662015-01-05 07:49:08 -08001934void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1935 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001936 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001937 return;
1938 }
reed4c21dc52015-06-25 12:32:03 -07001939 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001940 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001941 }
reed41af9662015-01-05 07:49:08 -08001942 this->onDrawBitmapNine(bitmap, center, dst, paint);
1943}
1944
reed71c3c762015-06-24 10:29:17 -07001945void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1946 const SkColor colors[], int count, SkXfermode::Mode mode,
1947 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001948 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001949 if (count <= 0) {
1950 return;
1951 }
1952 SkASSERT(atlas);
1953 SkASSERT(xform);
1954 SkASSERT(tex);
1955 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1956}
1957
reede47829b2015-08-06 10:02:53 -07001958void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1959 const SkPaint* paint, SrcRectConstraint constraint) {
1960 if (src) {
1961 this->drawImageRect(image, *src, dst, paint, constraint);
1962 } else {
1963 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1964 dst, paint, constraint);
1965 }
1966}
1967void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1968 const SkPaint* paint, SrcRectConstraint constraint) {
1969 if (src) {
1970 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1971 } else {
1972 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1973 dst, paint, constraint);
1974 }
1975}
1976
reed@android.com8a1c16f2008-12-17 15:59:43 +00001977//////////////////////////////////////////////////////////////////////////////
1978// These are the virtual drawing methods
1979//////////////////////////////////////////////////////////////////////////////
1980
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001981void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001982 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001983 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1984 }
1985}
1986
reed41af9662015-01-05 07:49:08 -08001987void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001988 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001989 this->internalDrawPaint(paint);
1990}
1991
1992void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001993 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001994
1995 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001996 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997 }
1998
reed@google.com4e2b3d32011-04-07 14:18:59 +00001999 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002000}
2001
reed41af9662015-01-05 07:49:08 -08002002void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2003 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002004 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002005 if ((long)count <= 0) {
2006 return;
2007 }
2008
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002009 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002010 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002011 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002012 // special-case 2 points (common for drawing a single line)
2013 if (2 == count) {
2014 r.set(pts[0], pts[1]);
2015 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002016 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002017 }
senorblanco87e066e2015-10-28 11:23:36 -07002018 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2019 return;
2020 }
2021 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002022 }
reed@google.coma584aed2012-05-16 14:06:02 +00002023
halcanary96fcdcc2015-08-27 07:41:13 -07002024 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002025
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002026 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002027
reed@android.com8a1c16f2008-12-17 15:59:43 +00002028 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002029 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002030 }
reed@google.com4b226022011-01-11 18:32:13 +00002031
reed@google.com4e2b3d32011-04-07 14:18:59 +00002032 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002033}
2034
reed41af9662015-01-05 07:49:08 -08002035void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002036 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002037 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002038 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002039 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002040 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2041 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2042 SkRect tmp(r);
2043 tmp.sort();
2044
senorblanco87e066e2015-10-28 11:23:36 -07002045 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2046 return;
2047 }
2048 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002049 }
reed@google.com4b226022011-01-11 18:32:13 +00002050
reedc83a2972015-07-16 07:40:45 -07002051 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002052
2053 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002054 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002055 }
2056
reed@google.com4e2b3d32011-04-07 14:18:59 +00002057 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002058}
2059
reed41af9662015-01-05 07:49:08 -08002060void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002061 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002062 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002063 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002064 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002065 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2066 return;
2067 }
2068 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002069 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002070
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002071 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002072
2073 while (iter.next()) {
2074 iter.fDevice->drawOval(iter, oval, looper.paint());
2075 }
2076
2077 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002078}
2079
reed41af9662015-01-05 07:49:08 -08002080void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002081 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002082 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002083 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002084 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002085 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2086 return;
2087 }
2088 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002089 }
2090
2091 if (rrect.isRect()) {
2092 // call the non-virtual version
2093 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002094 return;
2095 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002096 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002097 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2098 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002099 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002100
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002101 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002102
2103 while (iter.next()) {
2104 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2105 }
2106
2107 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002108}
2109
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002110void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2111 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002112 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002113 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002114 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002115 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2116 return;
2117 }
2118 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002119 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002120
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002121 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002122
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002123 while (iter.next()) {
2124 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2125 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002126
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002127 LOOPER_END
2128}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002129
reed41af9662015-01-05 07:49:08 -08002130void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002131 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002132 if (!path.isFinite()) {
2133 return;
2134 }
2135
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002136 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002137 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002138 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002139 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002140 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2141 return;
2142 }
2143 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002144 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002145
2146 const SkRect& r = path.getBounds();
2147 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002148 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002149 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002150 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002151 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002152 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002153
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002154 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002155
2156 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002157 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002158 }
2159
reed@google.com4e2b3d32011-04-07 14:18:59 +00002160 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002161}
2162
reed262a71b2015-12-05 13:07:27 -08002163bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002164 if (!paint.getImageFilter()) {
2165 return false;
2166 }
2167
2168 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002169 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002170 return false;
2171 }
2172
2173 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2174 // Once we can filter and the filter will return a result larger than itself, we should be
2175 // able to remove this constraint.
2176 // skbug.com/4526
2177 //
2178 SkPoint pt;
2179 ctm.mapXY(x, y, &pt);
2180 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2181 return ir.contains(fMCRec->fRasterClip.getBounds());
2182}
2183
reeda85d4d02015-05-06 12:56:48 -07002184void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002185 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002186 SkRect bounds = SkRect::MakeXYWH(x, y,
2187 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002188 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002189 SkRect tmp = bounds;
2190 if (paint) {
2191 paint->computeFastBounds(tmp, &tmp);
2192 }
2193 if (this->quickReject(tmp)) {
2194 return;
2195 }
reeda85d4d02015-05-06 12:56:48 -07002196 }
2197
2198 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002199 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002200 paint = lazy.init();
2201 }
reed262a71b2015-12-05 13:07:27 -08002202
2203 const bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2204 *paint);
2205 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2206
reeda85d4d02015-05-06 12:56:48 -07002207 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002208 const SkPaint& pnt = looper.paint();
2209 if (drawAsSprite && pnt.getImageFilter()) {
2210 SkBitmap bitmap;
2211 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2212 SkPoint pt;
2213 iter.fMatrix->mapXY(x, y, &pt);
2214 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2215 SkScalarRoundToInt(pt.fX),
2216 SkScalarRoundToInt(pt.fY), pnt);
2217 }
2218 } else {
2219 iter.fDevice->drawImage(iter, image, x, y, pnt);
2220 }
reeda85d4d02015-05-06 12:56:48 -07002221 }
2222
2223 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002224}
2225
reed41af9662015-01-05 07:49:08 -08002226void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002227 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002228 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002229 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002230 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002231 if (paint) {
2232 paint->computeFastBounds(dst, &storage);
2233 }
2234 if (this->quickReject(storage)) {
2235 return;
2236 }
reeda85d4d02015-05-06 12:56:48 -07002237 }
2238 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002239 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002240 paint = lazy.init();
2241 }
2242
senorblancoc41e7e12015-12-07 12:51:30 -08002243 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002244 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002245
2246 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002247 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002248 }
2249
2250 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002251}
2252
reed41af9662015-01-05 07:49:08 -08002253void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002254 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002255 SkDEBUGCODE(bitmap.validate();)
2256
reed33366972015-10-08 09:22:02 -07002257 if (bitmap.drawsNothing()) {
2258 return;
2259 }
2260
2261 SkLazyPaint lazy;
2262 if (nullptr == paint) {
2263 paint = lazy.init();
2264 }
2265
2266 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2267
2268 SkRect storage;
2269 const SkRect* bounds = nullptr;
2270 if (paint->canComputeFastBounds()) {
2271 bitmap.getBounds(&storage);
2272 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002273 SkRect tmp = storage;
2274 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2275 return;
2276 }
2277 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002278 }
reed@google.com4b226022011-01-11 18:32:13 +00002279
reed262a71b2015-12-05 13:07:27 -08002280 const bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2281 bitmap.height(), *paint);
2282 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002283
2284 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002285 const SkPaint& pnt = looper.paint();
2286 if (drawAsSprite && pnt.getImageFilter()) {
2287 SkPoint pt;
2288 iter.fMatrix->mapXY(x, y, &pt);
2289 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2290 SkScalarRoundToInt(pt.fX),
2291 SkScalarRoundToInt(pt.fY), pnt);
2292 } else {
2293 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2294 }
reed33366972015-10-08 09:22:02 -07002295 }
reed262a71b2015-12-05 13:07:27 -08002296
reed33366972015-10-08 09:22:02 -07002297 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002298}
2299
reed@google.com9987ec32011-09-07 11:57:52 +00002300// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002301void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002302 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002303 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002304 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305 return;
2306 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002307
halcanary96fcdcc2015-08-27 07:41:13 -07002308 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002309 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002310 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2311 return;
2312 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002313 }
reed@google.com3d608122011-11-21 15:16:16 +00002314
reed@google.com33535f32012-09-25 15:37:50 +00002315 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002316 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002317 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002319
senorblancoc41e7e12015-12-07 12:51:30 -08002320 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002321 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002322
reed@google.com33535f32012-09-25 15:37:50 +00002323 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002324 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002325 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002326
reed@google.com33535f32012-09-25 15:37:50 +00002327 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328}
2329
reed41af9662015-01-05 07:49:08 -08002330void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002331 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002332 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002333 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002334 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002335}
2336
reed4c21dc52015-06-25 12:32:03 -07002337void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2338 const SkPaint* paint) {
2339 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2340
halcanary96fcdcc2015-08-27 07:41:13 -07002341 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002342 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002343 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2344 return;
2345 }
reed@google.com3d608122011-11-21 15:16:16 +00002346 }
reed4c21dc52015-06-25 12:32:03 -07002347
2348 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002349 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002350 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002351 }
reed4c21dc52015-06-25 12:32:03 -07002352
senorblancoc41e7e12015-12-07 12:51:30 -08002353 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002354
2355 while (iter.next()) {
2356 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002357 }
reed4c21dc52015-06-25 12:32:03 -07002358
2359 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002360}
2361
reed41af9662015-01-05 07:49:08 -08002362void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2363 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002364 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002365 SkDEBUGCODE(bitmap.validate();)
2366
halcanary96fcdcc2015-08-27 07:41:13 -07002367 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002368 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002369 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2370 return;
2371 }
reed4c21dc52015-06-25 12:32:03 -07002372 }
2373
2374 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002375 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002376 paint = lazy.init();
2377 }
2378
senorblancoc41e7e12015-12-07 12:51:30 -08002379 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002380
2381 while (iter.next()) {
2382 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2383 }
2384
2385 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002386}
2387
reed@google.comf67e4cf2011-03-15 20:56:58 +00002388class SkDeviceFilteredPaint {
2389public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002390 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002391 uint32_t filteredFlags = device->filterTextFlags(paint);
2392 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002393 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002394 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002395 fPaint = newPaint;
2396 } else {
2397 fPaint = &paint;
2398 }
2399 }
2400
reed@google.comf67e4cf2011-03-15 20:56:58 +00002401 const SkPaint& paint() const { return *fPaint; }
2402
2403private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002404 const SkPaint* fPaint;
2405 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002406};
2407
bungeman@google.com52c748b2011-08-22 21:30:43 +00002408void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2409 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002410 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002411 draw.fDevice->drawRect(draw, r, paint);
2412 } else {
2413 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002414 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002415 draw.fDevice->drawRect(draw, r, p);
2416 }
2417}
2418
2419void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2420 const char text[], size_t byteLength,
2421 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002422 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002423
2424 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002425 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002426 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002427 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002428 return;
2429 }
2430
2431 SkScalar width = 0;
2432 SkPoint start;
2433
2434 start.set(0, 0); // to avoid warning
2435 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2436 SkPaint::kStrikeThruText_Flag)) {
2437 width = paint.measureText(text, byteLength);
2438
2439 SkScalar offsetX = 0;
2440 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2441 offsetX = SkScalarHalf(width);
2442 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2443 offsetX = width;
2444 }
2445 start.set(x - offsetX, y);
2446 }
2447
2448 if (0 == width) {
2449 return;
2450 }
2451
2452 uint32_t flags = paint.getFlags();
2453
2454 if (flags & (SkPaint::kUnderlineText_Flag |
2455 SkPaint::kStrikeThruText_Flag)) {
2456 SkScalar textSize = paint.getTextSize();
2457 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2458 SkRect r;
2459
2460 r.fLeft = start.fX;
2461 r.fRight = start.fX + width;
2462
2463 if (flags & SkPaint::kUnderlineText_Flag) {
2464 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2465 start.fY);
2466 r.fTop = offset;
2467 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002468 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002469 }
2470 if (flags & SkPaint::kStrikeThruText_Flag) {
2471 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2472 start.fY);
2473 r.fTop = offset;
2474 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002475 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002476 }
2477 }
2478}
2479
reed@google.come0d9ce82014-04-23 04:00:17 +00002480void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2481 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002482 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002483
2484 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002485 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002486 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002487 DrawTextDecorations(iter, dfp.paint(),
2488 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002489 }
2490
reed@google.com4e2b3d32011-04-07 14:18:59 +00002491 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002492}
2493
reed@google.come0d9ce82014-04-23 04:00:17 +00002494void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2495 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002496 SkPoint textOffset = SkPoint::Make(0, 0);
2497
halcanary96fcdcc2015-08-27 07:41:13 -07002498 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002499
reed@android.com8a1c16f2008-12-17 15:59:43 +00002500 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002501 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002502 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002503 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002504 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002505
reed@google.com4e2b3d32011-04-07 14:18:59 +00002506 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002507}
2508
reed@google.come0d9ce82014-04-23 04:00:17 +00002509void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2510 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002511
2512 SkPoint textOffset = SkPoint::Make(0, constY);
2513
halcanary96fcdcc2015-08-27 07:41:13 -07002514 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002515
reed@android.com8a1c16f2008-12-17 15:59:43 +00002516 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002517 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002518 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002519 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002520 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002521
reed@google.com4e2b3d32011-04-07 14:18:59 +00002522 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002523}
2524
reed@google.come0d9ce82014-04-23 04:00:17 +00002525void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2526 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002527 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002528
reed@android.com8a1c16f2008-12-17 15:59:43 +00002529 while (iter.next()) {
2530 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002531 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002532 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002533
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002534 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002535}
2536
fmalita00d5c2c2014-08-21 08:53:26 -07002537void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2538 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002539
fmalita85d5eb92015-03-04 11:20:12 -08002540 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002541 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002542 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002543 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002544 SkRect tmp;
2545 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2546 return;
2547 }
2548 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002549 }
2550
fmalita024f9962015-03-03 19:08:17 -08002551 // We cannot filter in the looper as we normally do, because the paint is
2552 // incomplete at this point (text-related attributes are embedded within blob run paints).
2553 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002554 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002555
fmalita85d5eb92015-03-04 11:20:12 -08002556 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002557
fmalitaaa1b9122014-08-28 14:32:24 -07002558 while (iter.next()) {
2559 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002560 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002561 }
2562
fmalitaaa1b9122014-08-28 14:32:24 -07002563 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002564
2565 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002566}
2567
reed@google.come0d9ce82014-04-23 04:00:17 +00002568// These will become non-virtual, so they always call the (virtual) onDraw... method
2569void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2570 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002571 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002572 this->onDrawText(text, byteLength, x, y, paint);
2573}
2574void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2575 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002576 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002577 this->onDrawPosText(text, byteLength, pos, paint);
2578}
2579void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2580 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002581 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002582 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2583}
2584void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2585 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002586 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002587 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2588}
fmalita00d5c2c2014-08-21 08:53:26 -07002589void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2590 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002591 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002592 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002593 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002594}
reed@google.come0d9ce82014-04-23 04:00:17 +00002595
reed41af9662015-01-05 07:49:08 -08002596void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2597 const SkPoint verts[], const SkPoint texs[],
2598 const SkColor colors[], SkXfermode* xmode,
2599 const uint16_t indices[], int indexCount,
2600 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002601 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002602 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002603
reed@android.com8a1c16f2008-12-17 15:59:43 +00002604 while (iter.next()) {
2605 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002606 colors, xmode, indices, indexCount,
2607 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002608 }
reed@google.com4b226022011-01-11 18:32:13 +00002609
reed@google.com4e2b3d32011-04-07 14:18:59 +00002610 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002611}
2612
dandovb3c9d1c2014-08-12 08:34:29 -07002613void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2614 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002615 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002616 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002617 return;
2618 }
mtklein6cfa73a2014-08-13 13:33:49 -07002619
dandovecfff212014-08-04 10:02:00 -07002620 // Since a patch is always within the convex hull of the control points, we discard it when its
2621 // bounding rectangle is completely outside the current clip.
2622 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002623 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002624 if (this->quickReject(bounds)) {
2625 return;
2626 }
mtklein6cfa73a2014-08-13 13:33:49 -07002627
dandovb3c9d1c2014-08-12 08:34:29 -07002628 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2629}
2630
2631void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2632 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2633
halcanary96fcdcc2015-08-27 07:41:13 -07002634 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002635
dandovecfff212014-08-04 10:02:00 -07002636 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002637 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002638 }
mtklein6cfa73a2014-08-13 13:33:49 -07002639
dandovecfff212014-08-04 10:02:00 -07002640 LOOPER_END
2641}
2642
reeda8db7282015-07-07 10:22:31 -07002643void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002644 RETURN_ON_NULL(dr);
2645 if (x || y) {
2646 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2647 this->onDrawDrawable(dr, &matrix);
2648 } else {
2649 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002650 }
2651}
2652
reeda8db7282015-07-07 10:22:31 -07002653void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002654 RETURN_ON_NULL(dr);
2655 if (matrix && matrix->isIdentity()) {
2656 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002657 }
reede3b38ce2016-01-08 09:18:44 -08002658 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002659}
2660
2661void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2662 SkRect bounds = dr->getBounds();
2663 if (matrix) {
2664 matrix->mapRect(&bounds);
2665 }
2666 if (this->quickReject(bounds)) {
2667 return;
2668 }
2669 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002670}
2671
reed71c3c762015-06-24 10:29:17 -07002672void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2673 const SkColor colors[], int count, SkXfermode::Mode mode,
2674 const SkRect* cull, const SkPaint* paint) {
2675 if (cull && this->quickReject(*cull)) {
2676 return;
2677 }
2678
2679 SkPaint pnt;
2680 if (paint) {
2681 pnt = *paint;
2682 }
2683
halcanary96fcdcc2015-08-27 07:41:13 -07002684 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002685 while (iter.next()) {
2686 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2687 }
2688 LOOPER_END
2689}
2690
reed@android.com8a1c16f2008-12-17 15:59:43 +00002691//////////////////////////////////////////////////////////////////////////////
2692// These methods are NOT virtual, and therefore must call back into virtual
2693// methods, rather than actually drawing themselves.
2694//////////////////////////////////////////////////////////////////////////////
2695
2696void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002697 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002698 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002699 SkPaint paint;
2700
2701 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002702 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002703 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002704 }
2705 this->drawPaint(paint);
2706}
2707
reed@android.com845fdac2009-06-23 03:01:32 +00002708void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002709 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002710 SkPaint paint;
2711
2712 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002713 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002714 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002715 }
2716 this->drawPaint(paint);
2717}
2718
2719void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002720 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002722
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 pt.set(x, y);
2724 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2725}
2726
2727void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002728 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002729 SkPoint pt;
2730 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002731
reed@android.com8a1c16f2008-12-17 15:59:43 +00002732 pt.set(x, y);
2733 paint.setColor(color);
2734 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2735}
2736
2737void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2738 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002739 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002741
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742 pts[0].set(x0, y0);
2743 pts[1].set(x1, y1);
2744 this->drawPoints(kLines_PointMode, 2, pts, paint);
2745}
2746
2747void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2748 SkScalar right, SkScalar bottom,
2749 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002750 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 SkRect r;
2752
2753 r.set(left, top, right, bottom);
2754 this->drawRect(r, paint);
2755}
2756
2757void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2758 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002759 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002760 if (radius < 0) {
2761 radius = 0;
2762 }
2763
2764 SkRect r;
2765 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002766 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767}
2768
2769void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2770 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002771 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772 if (rx > 0 && ry > 0) {
2773 if (paint.canComputeFastBounds()) {
2774 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002775 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776 return;
2777 }
2778 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002779 SkRRect rrect;
2780 rrect.setRectXY(r, rx, ry);
2781 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782 } else {
2783 this->drawRect(r, paint);
2784 }
2785}
2786
reed@android.com8a1c16f2008-12-17 15:59:43 +00002787void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2788 SkScalar sweepAngle, bool useCenter,
2789 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002790 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2792 this->drawOval(oval, paint);
2793 } else {
2794 SkPath path;
2795 if (useCenter) {
2796 path.moveTo(oval.centerX(), oval.centerY());
2797 }
2798 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2799 if (useCenter) {
2800 path.close();
2801 }
2802 this->drawPath(path, paint);
2803 }
2804}
2805
2806void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2807 const SkPath& path, SkScalar hOffset,
2808 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002809 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002810 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002811
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812 matrix.setTranslate(hOffset, vOffset);
2813 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2814}
2815
reed@android.comf76bacf2009-05-13 14:00:33 +00002816///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002817
2818/**
2819 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2820 * against the playback cost of recursing into the subpicture to get at its actual ops.
2821 *
2822 * For now we pick a conservatively small value, though measurement (and other heuristics like
2823 * the type of ops contained) may justify changing this value.
2824 */
2825#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002826
reedd5fa1a42014-08-09 11:08:05 -07002827void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002828 RETURN_ON_NULL(picture);
2829
reed1c2c4412015-04-30 13:09:24 -07002830 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002831 if (matrix && matrix->isIdentity()) {
2832 matrix = nullptr;
2833 }
2834 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2835 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2836 picture->playback(this);
2837 } else {
2838 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002839 }
2840}
robertphillips9b14f262014-06-04 05:40:44 -07002841
reedd5fa1a42014-08-09 11:08:05 -07002842void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2843 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002844 if (!paint || paint->canComputeFastBounds()) {
2845 SkRect bounds = picture->cullRect();
2846 if (paint) {
2847 paint->computeFastBounds(bounds, &bounds);
2848 }
2849 if (matrix) {
2850 matrix->mapRect(&bounds);
2851 }
2852 if (this->quickReject(bounds)) {
2853 return;
2854 }
2855 }
2856
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002857 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002858 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002859 // Canvas has to first give the device the opportunity to render
2860 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002861 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002862 return; // the device has rendered the entire picture
2863 }
2864 }
2865
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002866 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002867 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002868}
2869
reed@android.com8a1c16f2008-12-17 15:59:43 +00002870///////////////////////////////////////////////////////////////////////////////
2871///////////////////////////////////////////////////////////////////////////////
2872
2873SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002874 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002875
2876 SkASSERT(canvas);
2877
2878 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2879 fDone = !fImpl->next();
2880}
2881
2882SkCanvas::LayerIter::~LayerIter() {
2883 fImpl->~SkDrawIter();
2884}
2885
2886void SkCanvas::LayerIter::next() {
2887 fDone = !fImpl->next();
2888}
2889
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002890SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002891 return fImpl->getDevice();
2892}
2893
2894const SkMatrix& SkCanvas::LayerIter::matrix() const {
2895 return fImpl->getMatrix();
2896}
2897
2898const SkPaint& SkCanvas::LayerIter::paint() const {
2899 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002900 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002901 paint = &fDefaultPaint;
2902 }
2903 return *paint;
2904}
2905
2906const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2907int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2908int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002909
2910///////////////////////////////////////////////////////////////////////////////
2911
fmalitac3b589a2014-06-05 12:40:07 -07002912SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002913
2914///////////////////////////////////////////////////////////////////////////////
2915
2916static bool supported_for_raster_canvas(const SkImageInfo& info) {
2917 switch (info.alphaType()) {
2918 case kPremul_SkAlphaType:
2919 case kOpaque_SkAlphaType:
2920 break;
2921 default:
2922 return false;
2923 }
2924
2925 switch (info.colorType()) {
2926 case kAlpha_8_SkColorType:
2927 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002928 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002929 break;
2930 default:
2931 return false;
2932 }
2933
2934 return true;
2935}
2936
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002937SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2938 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002939 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002940 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002941
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002942 SkBitmap bitmap;
2943 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002944 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002945 }
halcanary385fe4d2015-08-26 13:07:48 -07002946 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002947}
reedd5fa1a42014-08-09 11:08:05 -07002948
2949///////////////////////////////////////////////////////////////////////////////
2950
2951SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002952 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002953 : fCanvas(canvas)
2954 , fSaveCount(canvas->getSaveCount())
2955{
bsalomon49f085d2014-09-05 13:34:00 -07002956 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002957 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002958 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002959 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002960 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002961 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002962 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002963 canvas->save();
2964 }
mtklein6cfa73a2014-08-13 13:33:49 -07002965
bsalomon49f085d2014-09-05 13:34:00 -07002966 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002967 canvas->concat(*matrix);
2968 }
2969}
2970
2971SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2972 fCanvas->restoreToCount(fSaveCount);
2973}