blob: ce99546728a09171bf57aa51cb30daadeb42ede2 [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
8#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -07009#include "SkCanvasPriv.h"
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000010#include "SkBitmapDevice.h"
senorblanco@chromium.org9c397442012-09-27 21:57:45 +000011#include "SkDeviceImageFilterProxy.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080013#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDrawFilter.h"
15#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070016#include "SkImage.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000017#include "SkMetaData.h"
caryclark@google.com45a75fb2013-04-25 13:34:40 +000018#include "SkPathOps.h"
dandovb3c9d1c2014-08-12 08:34:29 -070019#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000020#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000021#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080022#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000023#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000024#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000025#include "SkSurface_Base.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000026#include "SkTemplates.h"
fmalita7ba7aa72014-08-29 09:46:36 -070027#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000028#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000029#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080030#include "SkTraceEvent.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000031#include "SkUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000032
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000033#if SK_SUPPORT_GPU
34#include "GrRenderTarget.h"
35#endif
36
reedd990e2f2014-12-22 11:58:30 -080037static bool gIgnoreSaveLayerBounds;
38void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
39 gIgnoreSaveLayerBounds = ignore;
40}
41bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
42 return gIgnoreSaveLayerBounds;
43}
44
reed0acf1b42014-12-22 16:12:38 -080045static bool gTreatSpriteAsBitmap;
46void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
47 gTreatSpriteAsBitmap = spriteAsBitmap;
48}
49bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
50 return gTreatSpriteAsBitmap;
51}
52
reed@google.comda17f752012-08-16 18:27:05 +000053// experimental for faster tiled drawing...
54//#define SK_ENABLE_CLIP_QUICKREJECT
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000055
reed@android.com8a1c16f2008-12-17 15:59:43 +000056//#define SK_TRACE_SAVERESTORE
57
58#ifdef SK_TRACE_SAVERESTORE
59 static int gLayerCounter;
60 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
61 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
62
63 static int gRecCounter;
64 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
65 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
66
67 static int gCanvasCounter;
68 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
69 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
70#else
71 #define inc_layer()
72 #define dec_layer()
73 #define inc_rec()
74 #define dec_rec()
75 #define inc_canvas()
76 #define dec_canvas()
77#endif
78
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +000079typedef SkTLazy<SkPaint> SkLazyPaint;
80
reed@google.com97af1a62012-08-28 12:19:02 +000081void SkCanvas::predrawNotify() {
82 if (fSurfaceBase) {
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +000083 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
reed@google.com97af1a62012-08-28 12:19:02 +000084 }
85}
86
reed@android.com8a1c16f2008-12-17 15:59:43 +000087///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000088
reed4a8126e2014-09-22 07:29:03 -070089static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
90 const uint32_t propFlags = props.flags();
91 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
92 flags &= ~SkPaint::kDither_Flag;
93 }
94 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
95 flags &= ~SkPaint::kAntiAlias_Flag;
96 }
97 return flags;
98}
99
100///////////////////////////////////////////////////////////////////////////////
101
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000102/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 The clip/matrix/proc are fields that reflect the top of the save/restore
104 stack. Whenever the canvas changes, it marks a dirty flag, and then before
105 these are used (assuming we're not on a layer) we rebuild these cache
106 values: they reflect the top of the save stack, but translated and clipped
107 by the device's XY offset and bitmap-bounds.
108*/
109struct DeviceCM {
110 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000111 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000112 SkRasterClip fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113 const SkMatrix* fMatrix;
reed@google.com6f8f2922011-03-04 22:27:10 +0000114 SkPaint* fPaint; // may be null (in the future)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115
reedd9544982014-09-09 18:46:22 -0700116 DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas,
117 bool conservativeRasterClip)
118 : fNext(NULL)
119 , fClip(conservativeRasterClip)
120 {
121 if (NULL != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000123 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 }
reed@google.com4b226022011-01-11 18:32:13 +0000125 fDevice = device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000127 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000129 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700130 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000131 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 fDevice->unref();
133 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000134 SkDELETE(fPaint);
135 }
reed@google.com4b226022011-01-11 18:32:13 +0000136
reed@google.com045e62d2011-10-24 12:19:46 +0000137 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
138 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000139 int x = fDevice->getOrigin().x();
140 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141 int width = fDevice->width();
142 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000143
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 if ((x | y) == 0) {
145 fMatrix = &totalMatrix;
146 fClip = totalClip;
147 } else {
148 fMatrixStorage = totalMatrix;
149 fMatrixStorage.postTranslate(SkIntToScalar(-x),
150 SkIntToScalar(-y));
151 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000152
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 totalClip.translate(-x, -y, &fClip);
154 }
155
reed@google.com045e62d2011-10-24 12:19:46 +0000156 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157
158 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000159
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000161 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 SkRegion::kDifference_Op);
163 }
reed@google.com4b226022011-01-11 18:32:13 +0000164
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000165 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
166
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167#ifdef SK_DEBUG
168 if (!fClip.isEmpty()) {
169 SkIRect deviceR;
170 deviceR.set(0, 0, width, height);
171 SkASSERT(deviceR.contains(fClip.getBounds()));
172 }
173#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000174 }
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176private:
bsalomon@google.com0e354aa2012-10-08 20:44:25 +0000177 SkMatrix fMatrixStorage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178};
179
180/* This is the record we keep for each save/restore level in the stack.
181 Since a level optionally copies the matrix and/or stack, we have pointers
182 for these fields. If the value is copied for this level, the copy is
183 stored in the ...Storage field, and the pointer points to that. If the
184 value is not copied for this level, we ignore ...Storage, and just point
185 at the corresponding value in the previous level in the stack.
186*/
187class SkCanvas::MCRec {
188public:
reed1f836ee2014-07-07 07:49:34 -0700189 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700190 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 /* If there are any layers in the stack, this points to the top-most
192 one that is at or below this level in the stack (so we know what
193 bitmap/device to draw into from this level. This value is NOT
194 reference counted, since the real owner is either our fLayer field,
195 or a previous one in a lower level.)
196 */
reed2ff1fce2014-12-11 07:07:37 -0800197 DeviceCM* fTopLayer;
198 SkRasterClip fRasterClip;
199 SkMatrix fMatrix;
200 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201
reedd9544982014-09-09 18:46:22 -0700202 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
reedd9544982014-09-09 18:46:22 -0700203 fFilter = NULL;
204 fLayer = NULL;
205 fTopLayer = NULL;
reed2ff1fce2014-12-11 07:07:37 -0800206 fMatrix.reset();
207 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700208
reedd9544982014-09-09 18:46:22 -0700209 // don't bother initializing fNext
210 inc_rec();
211 }
reed2ff1fce2014-12-11 07:07:37 -0800212 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700213 fFilter = SkSafeRef(prev.fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 fLayer = NULL;
reedd9544982014-09-09 18:46:22 -0700215 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800216 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700217
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 // don't bother initializing fNext
219 inc_rec();
220 }
221 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000222 SkSafeUnref(fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 SkDELETE(fLayer);
224 dec_rec();
225 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226};
227
228class SkDrawIter : public SkDraw {
229public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000230 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000231 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000232 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 canvas->updateDeviceCMCache();
234
joshualittde358a92015-02-05 08:19:35 -0800235 fClipStack = canvas->fClipStack.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000237 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 }
reed@google.com4b226022011-01-11 18:32:13 +0000239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 bool next() {
241 // skip over recs with empty clips
242 if (fSkipEmptyClips) {
243 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
244 fCurrLayer = fCurrLayer->fNext;
245 }
246 }
247
reed@google.comf68c5e22012-02-24 16:38:58 +0000248 const DeviceCM* rec = fCurrLayer;
249 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250
251 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000252 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
253 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 fDevice = rec->fDevice;
255 fBitmap = &fDevice->accessBitmap(true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000257 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258
259 fCurrLayer = rec->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 // fCurrLayer may be NULL now
reed@android.com199f1082009-06-10 02:12:47 +0000261
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262 return true;
263 }
264 return false;
265 }
reed@google.com4b226022011-01-11 18:32:13 +0000266
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000267 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000268 int getX() const { return fDevice->getOrigin().x(); }
269 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270 const SkMatrix& getMatrix() const { return *fMatrix; }
271 const SkRegion& getClip() const { return *fClip; }
272 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000273
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274private:
275 SkCanvas* fCanvas;
276 const DeviceCM* fCurrLayer;
277 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 SkBool8 fSkipEmptyClips;
279
280 typedef SkDraw INHERITED;
281};
282
283/////////////////////////////////////////////////////////////////////////////
284
285class AutoDrawLooper {
286public:
reed4a8126e2014-09-22 07:29:03 -0700287 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000288 bool skipLayerForImageFilter = false,
289 const SkRect* bounds = NULL) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000290 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700292 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000293 fSaveCount = canvas->getSaveCount();
reed@google.com8926b162012-03-23 15:36:36 +0000294 fDoClearImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000295 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296
reed@google.com8926b162012-03-23 15:36:36 +0000297 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
298 SkPaint tmp;
299 tmp.setImageFilter(fOrigPaint.getImageFilter());
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000300 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
301 true, SkCanvas::kFullLayer_SaveLayerStrategy);
reed@google.com8926b162012-03-23 15:36:36 +0000302 // we'll clear the imageFilter for the actual draws in next(), so
303 // it will only be applied during the restore().
304 fDoClearImageFilter = true;
305 }
306
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000307 if (SkDrawLooper* looper = paint.getLooper()) {
308 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
309 looper->contextSize());
310 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000311 fIsSimple = false;
312 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000313 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000314 // can we be marked as simple?
315 fIsSimple = !fFilter && !fDoClearImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000316 }
piotaixrb5fae932014-09-24 13:03:30 -0700317
reed4a8126e2014-09-22 07:29:03 -0700318 uint32_t oldFlags = paint.getFlags();
319 fNewPaintFlags = filter_paint_flags(props, oldFlags);
320 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
321 SkPaint* paint = fLazyPaint.set(fOrigPaint);
322 paint->setFlags(fNewPaintFlags);
323 fPaint = paint;
324 // if we're not simple, doNext() will take care of calling setFlags()
325 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000326 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000327
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 ~AutoDrawLooper() {
reed@google.com8926b162012-03-23 15:36:36 +0000329 if (fDoClearImageFilter) {
330 fCanvas->internalRestore();
331 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000332 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000334
reed@google.com4e2b3d32011-04-07 14:18:59 +0000335 const SkPaint& paint() const {
336 SkASSERT(fPaint);
337 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000339
reed@google.com129ec222012-05-15 13:24:09 +0000340 bool next(SkDrawFilter::Type drawType) {
341 if (fDone) {
342 return false;
343 } else if (fIsSimple) {
344 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000345 return !fPaint->nothingToDraw();
346 } else {
347 return this->doNext(drawType);
348 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000349 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000350
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000352 SkLazyPaint fLazyPaint;
353 SkCanvas* fCanvas;
354 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000355 SkDrawFilter* fFilter;
356 const SkPaint* fPaint;
357 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700358 uint32_t fNewPaintFlags;
reed@google.com8926b162012-03-23 15:36:36 +0000359 bool fDoClearImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000360 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000361 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000362 SkDrawLooper::Context* fLooperContext;
363 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000364
365 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366};
367
reed@google.com129ec222012-05-15 13:24:09 +0000368bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000369 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000370 SkASSERT(!fIsSimple);
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000371 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000372
373 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700374 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000375
376 if (fDoClearImageFilter) {
377 paint->setImageFilter(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000378 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000379
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000380 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000381 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000382 return false;
383 }
384 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000385 if (!fFilter->filter(paint, drawType)) {
386 fDone = true;
387 return false;
388 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000389 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000390 // no looper means we only draw once
391 fDone = true;
392 }
393 }
394 fPaint = paint;
395
396 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000397 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000398 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000399 }
400
401 // call this after any possible paint modifiers
402 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000403 fPaint = NULL;
404 return false;
405 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000406 return true;
407}
408
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409////////// macros to place around the internal draw calls //////////////////
410
reed@google.com8926b162012-03-23 15:36:36 +0000411#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000412 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700413 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000414 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000415 SkDrawIter iter(this);
416
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000417#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000418 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700419 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000420 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000422
reed@google.com4e2b3d32011-04-07 14:18:59 +0000423#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424
425////////////////////////////////////////////////////////////////////////////
426
reedd9544982014-09-09 18:46:22 -0700427SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
428 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000429 fCachedLocalClipBounds.setEmpty();
430 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000431 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000432 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700433 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800434 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000435 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436
437 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700438 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439
reedd9544982014-09-09 18:46:22 -0700440 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442
reed@google.com97af1a62012-08-28 12:19:02 +0000443 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000444
joshualittde358a92015-02-05 08:19:35 -0800445 fClipStack.reset(SkNEW(SkClipStack));
446
reedf92c8662014-08-18 08:02:43 -0700447 if (device) {
reedb2db8982014-11-13 12:41:02 -0800448 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700449 if (device->forceConservativeRasterClip()) {
450 fConservativeRasterClip = true;
451 }
reedf92c8662014-08-18 08:02:43 -0700452 device->onAttachToCanvas(this);
453 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800454 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700455 }
456 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000457}
458
reed@google.comcde92112011-07-06 20:00:52 +0000459SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000460 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700461 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000462{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000463 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000464
reedd9544982014-09-09 18:46:22 -0700465 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000466}
467
reedd9544982014-09-09 18:46:22 -0700468static SkBitmap make_nopixels(int width, int height) {
469 SkBitmap bitmap;
470 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
471 return bitmap;
472}
473
474class SkNoPixelsBitmapDevice : public SkBitmapDevice {
475public:
reed78e27682014-11-19 08:04:34 -0800476 SkNoPixelsBitmapDevice(const SkIRect& bounds)
477 : INHERITED(make_nopixels(bounds.width(), bounds.height()))
478 {
479 this->setOrigin(bounds.x(), bounds.y());
480 }
reedd9544982014-09-09 18:46:22 -0700481
482private:
piotaixrb5fae932014-09-24 13:03:30 -0700483
reedd9544982014-09-09 18:46:22 -0700484 typedef SkBitmapDevice INHERITED;
485};
486
reed96a857e2015-01-25 10:33:58 -0800487SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000488 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800489 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000490{
491 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700492
reed78e27682014-11-19 08:04:34 -0800493 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
494 (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700495}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000496
reed78e27682014-11-19 08:04:34 -0800497SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700498 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700499 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700500{
501 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700502
reed78e27682014-11-19 08:04:34 -0800503 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700504}
505
reed4a8126e2014-09-22 07:29:03 -0700506SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700507 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700508 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700509{
510 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700511
reedd9544982014-09-09 18:46:22 -0700512 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000513}
514
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000515SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000516 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700517 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000518{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700520
reedd9544982014-09-09 18:46:22 -0700521 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000522}
523
reed4a8126e2014-09-22 07:29:03 -0700524SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700525 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700526 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700527{
528 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700529
reed4a8126e2014-09-22 07:29:03 -0700530 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
531 this->init(device, kDefault_InitFlags);
532}
reed29c857d2014-09-21 10:25:07 -0700533
reed4a8126e2014-09-22 07:29:03 -0700534SkCanvas::SkCanvas(const SkBitmap& bitmap)
535 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
536 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
537{
538 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700539
reed4a8126e2014-09-22 07:29:03 -0700540 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
541 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000542}
543
544SkCanvas::~SkCanvas() {
545 // free up the contents of our deque
546 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000547
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548 this->internalRestore(); // restore the last, since we're going away
549
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000550 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000551
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552 dec_canvas();
553}
554
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555SkDrawFilter* SkCanvas::getDrawFilter() const {
556 return fMCRec->fFilter;
557}
558
559SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
560 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
561 return filter;
562}
563
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000564SkMetaData& SkCanvas::getMetaData() {
565 // metadata users are rare, so we lazily allocate it. If that changes we
566 // can decide to just make it a field in the device (rather than a ptr)
567 if (NULL == fMetaData) {
568 fMetaData = new SkMetaData;
569 }
570 return *fMetaData;
571}
572
reed@android.com8a1c16f2008-12-17 15:59:43 +0000573///////////////////////////////////////////////////////////////////////////////
574
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000575void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000576 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000577 if (device) {
578 device->flush();
579 }
580}
581
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000582SkISize SkCanvas::getTopLayerSize() const {
583 SkBaseDevice* d = this->getTopDevice();
584 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
585}
586
587SkIPoint SkCanvas::getTopLayerOrigin() const {
588 SkBaseDevice* d = this->getTopDevice();
589 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
590}
591
592SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000593 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000594 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
595}
596
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000597SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000598 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000599 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600 SkASSERT(rec && rec->fLayer);
601 return rec->fLayer->fDevice;
602}
603
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000604SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000605 if (updateMatrixClip) {
606 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
607 }
reed@google.com9266fed2011-03-30 00:18:03 +0000608 return fMCRec->fTopLayer->fDevice;
609}
610
commit-bot@chromium.org403f8d72014-02-17 15:24:26 +0000611SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 // return root device
reed@google.com4c09d5c2011-02-22 13:16:38 +0000613 SkDeque::F2BIter iter(fMCStack);
614 MCRec* rec = (MCRec*)iter.next();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615 SkASSERT(rec && rec->fLayer);
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000616 SkBaseDevice* rootDevice = rec->fLayer->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000617
618 if (rootDevice == device) {
619 return device;
620 }
reed@google.com4b226022011-01-11 18:32:13 +0000621
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622 if (device) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000623 device->onAttachToCanvas(this);
reedb2db8982014-11-13 12:41:02 -0800624 device->initForRootLayer(fProps.pixelGeometry());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625 }
626 if (rootDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000627 rootDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628 }
629
630 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
631 rootDevice = device;
632
633 fDeviceCMDirty = true;
reed@google.com4b226022011-01-11 18:32:13 +0000634
reed@android.com8a1c16f2008-12-17 15:59:43 +0000635 /* Now we update our initial region to have the bounds of the new device,
636 and then intersect all of the clips in our stack with these bounds,
637 to ensure that we can't draw outside of the device's bounds (and trash
638 memory).
reed@google.com4b226022011-01-11 18:32:13 +0000639
reed@android.com8a1c16f2008-12-17 15:59:43 +0000640 NOTE: this is only a partial-fix, since if the new device is larger than
641 the previous one, we don't know how to "enlarge" the clips in our stack,
reed@google.com4b226022011-01-11 18:32:13 +0000642 so drawing may be artificially restricted. Without keeping a history of
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
644 reconstruct the correct clips, so this approximation will have to do.
645 The caller really needs to restore() back to the base if they want to
646 accurately take advantage of the new device bounds.
647 */
648
reed@google.com42aea282012-03-28 16:19:15 +0000649 SkIRect bounds;
650 if (device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000651 bounds.set(0, 0, device->width(), device->height());
reed@google.com42aea282012-03-28 16:19:15 +0000652 } else {
653 bounds.setEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654 }
reed@google.com42aea282012-03-28 16:19:15 +0000655 // now jam our 1st clip to be bounds, and intersect the rest with that
reed1f836ee2014-07-07 07:49:34 -0700656 rec->fRasterClip.setRect(bounds);
reed@google.com42aea282012-03-28 16:19:15 +0000657 while ((rec = (MCRec*)iter.next()) != NULL) {
reed1f836ee2014-07-07 07:49:34 -0700658 (void)rec->fRasterClip.op(bounds, SkRegion::kIntersect_Op);
reed@google.com42aea282012-03-28 16:19:15 +0000659 }
660
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 return device;
662}
663
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000664bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
665 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
666 return false;
667 }
668
669 bool weAllocated = false;
670 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700671 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000672 return false;
673 }
674 weAllocated = true;
675 }
676
677 SkBitmap bm(*bitmap);
678 bm.lockPixels();
679 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
680 return true;
681 }
682
683 if (weAllocated) {
684 bitmap->setPixelRef(NULL);
685 }
686 return false;
687}
reed@google.com51df9e32010-12-23 19:29:18 +0000688
bsalomon@google.comc6980972011-11-02 19:57:21 +0000689bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000690 SkIRect r = srcRect;
691 const SkISize size = this->getBaseLayerSize();
692 if (!r.intersect(0, 0, size.width(), size.height())) {
693 bitmap->reset();
694 return false;
695 }
696
reed84825042014-09-02 12:50:45 -0700697 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000698 // bitmap will already be reset.
699 return false;
700 }
701 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
702 bitmap->reset();
703 return false;
704 }
705 return true;
706}
707
reed96472de2014-12-10 09:53:42 -0800708bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000709 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000710 if (!device) {
711 return false;
712 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000713 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800714
reed96472de2014-12-10 09:53:42 -0800715 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
716 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000717 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000718 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000719
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000720 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800721 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000722}
723
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000724bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
725 if (bitmap.getTexture()) {
726 return false;
727 }
728 SkBitmap bm(bitmap);
729 bm.lockPixels();
730 if (bm.getPixels()) {
731 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
732 }
733 return false;
734}
735
736bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
737 int x, int y) {
738 switch (origInfo.colorType()) {
739 case kUnknown_SkColorType:
740 case kIndex_8_SkColorType:
741 return false;
742 default:
743 break;
744 }
745 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
746 return false;
747 }
748
749 const SkISize size = this->getBaseLayerSize();
750 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
751 if (!target.intersect(0, 0, size.width(), size.height())) {
752 return false;
753 }
754
755 SkBaseDevice* device = this->getDevice();
756 if (!device) {
757 return false;
758 }
759
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000760 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700761 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000762
763 // if x or y are negative, then we have to adjust pixels
764 if (x > 0) {
765 x = 0;
766 }
767 if (y > 0) {
768 y = 0;
769 }
770 // here x,y are either 0 or negative
771 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
772
reed4af35f32014-06-27 17:47:49 -0700773 // Tell our owning surface to bump its generation ID
774 this->predrawNotify();
775
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000776 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000777 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000778}
reed@google.com51df9e32010-12-23 19:29:18 +0000779
junov@google.com4370aed2012-01-18 16:21:08 +0000780SkCanvas* SkCanvas::canvasForDrawIter() {
781 return this;
782}
783
reed@android.com8a1c16f2008-12-17 15:59:43 +0000784//////////////////////////////////////////////////////////////////////////////
785
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786void SkCanvas::updateDeviceCMCache() {
787 if (fDeviceCMDirty) {
788 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700789 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000791
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792 if (NULL == layer->fNext) { // only one layer
joshualittde358a92015-02-05 08:19:35 -0800793 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000795 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796 do {
joshualittde358a92015-02-05 08:19:35 -0800797 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000798 } while ((layer = layer->fNext) != NULL);
799 }
800 fDeviceCMDirty = false;
801 }
802}
803
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804///////////////////////////////////////////////////////////////////////////////
805
reed2ff1fce2014-12-11 07:07:37 -0800806void SkCanvas::checkForDeferredSave() {
807 if (fMCRec->fDeferredSaveCount > 0) {
808 fMCRec->fDeferredSaveCount -= 1;
809 this->doSave();
810 }
811}
812
reedf0090cb2014-11-26 08:55:51 -0800813int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800814#ifdef SK_DEBUG
815 int count = 0;
816 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
817 for (;;) {
818 const MCRec* rec = (const MCRec*)iter.next();
819 if (!rec) {
820 break;
821 }
822 count += 1 + rec->fDeferredSaveCount;
823 }
824 SkASSERT(count == fSaveCount);
825#endif
826 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800827}
828
829int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800830 fSaveCount += 1;
831 fMCRec->fDeferredSaveCount += 1;
832 return this->getSaveCount() - 1; // return our prev value
833}
834
835void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800836 this->willSave();
reed2ff1fce2014-12-11 07:07:37 -0800837 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800838}
839
840void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800841 if (fMCRec->fDeferredSaveCount > 0) {
842 SkASSERT(fSaveCount > 1);
843 fSaveCount -= 1;
844 fMCRec->fDeferredSaveCount -= 1;
845 } else {
846 // check for underflow
847 if (fMCStack.count() > 1) {
848 this->willRestore();
849 SkASSERT(fSaveCount > 1);
850 fSaveCount -= 1;
851 this->internalRestore();
852 this->didRestore();
853 }
reedf0090cb2014-11-26 08:55:51 -0800854 }
855}
856
857void SkCanvas::restoreToCount(int count) {
858 // sanity check
859 if (count < 1) {
860 count = 1;
861 }
mtkleinf0f14112014-12-12 08:46:25 -0800862
reedf0090cb2014-11-26 08:55:51 -0800863 int n = this->getSaveCount() - count;
864 for (int i = 0; i < n; ++i) {
865 this->restore();
866 }
867}
868
reed2ff1fce2014-12-11 07:07:37 -0800869void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700871 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000873
joshualittde358a92015-02-05 08:19:35 -0800874 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875}
876
reed@android.com8a1c16f2008-12-17 15:59:43 +0000877static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000878#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000879 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000880#else
881 return true;
882#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000883}
884
junov@chromium.orga907ac32012-02-24 21:54:07 +0000885bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000886 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000887 SkIRect clipBounds;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000888 SkRegion::Op op = SkRegion::kIntersect_Op;
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000889 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000890 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000891 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000892
893 if (imageFilter) {
reed1f836ee2014-07-07 07:49:34 -0700894 imageFilter->filterBounds(clipBounds, fMCRec->fMatrix, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000895 // Filters may grow the bounds beyond the device bounds.
896 op = SkRegion::kReplace_Op;
897 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000898 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700899 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000900 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000901
reed@android.com8a1c16f2008-12-17 15:59:43 +0000902 this->getTotalMatrix().mapRect(&r, *bounds);
903 r.roundOut(&ir);
904 // early exit if the layer's bounds are clipped out
905 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000906 if (bounds_affects_clip(flags)) {
reed1f836ee2014-07-07 07:49:34 -0700907 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000908 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000909 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000910 }
911 } else { // no user bounds, so just use the clip
912 ir = clipBounds;
913 }
914
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000915 if (bounds_affects_clip(flags)) {
joshualittde358a92015-02-05 08:19:35 -0800916 fClipStack->clipDevRect(ir, op);
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000917 // early exit if the clip is now empty
reed1f836ee2014-07-07 07:49:34 -0700918 if (!fMCRec->fRasterClip.op(ir, op)) {
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000919 return false;
920 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000921 }
922
923 if (intersection) {
924 *intersection = ir;
925 }
926 return true;
927}
928
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000929int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800930 if (gIgnoreSaveLayerBounds) {
931 bounds = NULL;
932 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000933 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reed2ff1fce2014-12-11 07:07:37 -0800934 fSaveCount += 1;
935 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy);
936 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000937}
938
reed2ff1fce2014-12-11 07:07:37 -0800939int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800940 if (gIgnoreSaveLayerBounds) {
941 bounds = NULL;
942 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000943 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reed2ff1fce2014-12-11 07:07:37 -0800944 fSaveCount += 1;
945 this->internalSaveLayer(bounds, paint, flags, false, strategy);
946 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000947}
948
reed2ff1fce2014-12-11 07:07:37 -0800949void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000950 bool justForImageFilter, SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000951#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000952 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000953#endif
954
junov@chromium.orga907ac32012-02-24 21:54:07 +0000955 // do this before we create the layer. We don't call the public save() since
956 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -0800957 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000958
959 fDeviceCMDirty = true;
960
961 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000962 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -0800963 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 }
965
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000966 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
967 // the clipRectBounds() call above?
968 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -0800969 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000970 }
971
reed@google.comb55deeb2012-01-06 14:43:09 +0000972 // Kill the imagefilter if our device doesn't allow it
973 SkLazyPaint lazyP;
974 if (paint && paint->getImageFilter()) {
975 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
reed@google.com8926b162012-03-23 15:36:36 +0000976 if (justForImageFilter) {
977 // early exit if the layer was just for the imageFilter
reed2ff1fce2014-12-11 07:07:37 -0800978 return;
reed@google.com8926b162012-03-23 15:36:36 +0000979 }
reed@google.comb55deeb2012-01-06 14:43:09 +0000980 SkPaint* p = lazyP.set(*paint);
981 p->setImageFilter(NULL);
982 paint = p;
983 }
984 }
985
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000986 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
987 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
988 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989
reedb2db8982014-11-13 12:41:02 -0800990 SkBaseDevice* device = this->getTopDevice();
991 if (NULL == device) {
992 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800993 return;
reed@google.com76dd2772012-01-05 21:15:07 +0000994 }
reedb2db8982014-11-13 12:41:02 -0800995
996 SkBaseDevice::Usage usage = SkBaseDevice::kSaveLayer_Usage;
997 if (paint && paint->getImageFilter()) {
998 usage = SkBaseDevice::kImageFilter_Usage;
999 }
1000 device = device->onCreateCompatibleDevice(SkBaseDevice::CreateInfo(info, usage,
1001 fProps.pixelGeometry()));
bungeman@google.come25c6842011-08-17 14:53:54 +00001002 if (NULL == device) {
1003 SkDebugf("Unable to create device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001004 return;
bungeman@google.come25c6842011-08-17 14:53:54 +00001005 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001006
reed@google.com6f8f2922011-03-04 22:27:10 +00001007 device->setOrigin(ir.fLeft, ir.fTop);
reedd9544982014-09-09 18:46:22 -07001008 DeviceCM* layer = SkNEW_ARGS(DeviceCM,
1009 (device, ir.fLeft, ir.fTop, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001010 device->unref();
1011
1012 layer->fNext = fMCRec->fTopLayer;
1013 fMCRec->fLayer = layer;
1014 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001015}
1016
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001017int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1018 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1019}
1020
reed@android.com8a1c16f2008-12-17 15:59:43 +00001021int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1022 SaveFlags flags) {
1023 if (0xFF == alpha) {
1024 return this->saveLayer(bounds, NULL, flags);
1025 } else {
1026 SkPaint tmpPaint;
1027 tmpPaint.setAlpha(alpha);
1028 return this->saveLayer(bounds, &tmpPaint, flags);
1029 }
1030}
1031
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032void SkCanvas::internalRestore() {
1033 SkASSERT(fMCStack.count() != 0);
1034
1035 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001036 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037
joshualittde358a92015-02-05 08:19:35 -08001038 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001039
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001040 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001041 DeviceCM* layer = fMCRec->fLayer; // may be null
1042 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1043 fMCRec->fLayer = NULL;
1044
1045 // now do the normal restore()
1046 fMCRec->~MCRec(); // balanced in save()
1047 fMCStack.pop_back();
1048 fMCRec = (MCRec*)fMCStack.back();
1049
1050 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1051 since if we're being recorded, we don't want to record this (the
1052 recorder will have already recorded the restore).
1053 */
bsalomon49f085d2014-09-05 13:34:00 -07001054 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001056 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001057 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1058 layer->fPaint);
1059 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001060 fDeviceCMDirty = true;
1061 }
1062 SkDELETE(layer);
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001063 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064}
1065
reed4a8126e2014-09-22 07:29:03 -07001066SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1067 if (NULL == props) {
1068 props = &fProps;
1069 }
1070 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001071}
1072
reed4a8126e2014-09-22 07:29:03 -07001073SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001074 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001075 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001076}
1077
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001078SkImageInfo SkCanvas::imageInfo() const {
1079 SkBaseDevice* dev = this->getDevice();
1080 if (dev) {
1081 return dev->imageInfo();
1082 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001083 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001084 }
1085}
1086
1087const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1088 return this->onPeekPixels(info, rowBytes);
1089}
1090
1091const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1092 SkBaseDevice* dev = this->getDevice();
1093 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1094}
1095
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001096void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1097 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1098 if (pixels && origin) {
1099 *origin = this->getTopDevice(false)->getOrigin();
1100 }
1101 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001102}
1103
1104void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1105 SkBaseDevice* dev = this->getTopDevice();
1106 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1107}
1108
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001109SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1110 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1111 if (NULL == fAddr) {
1112 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001113 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001114 return; // failure, fAddr is NULL
1115 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001116 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1117 return; // failure, fAddr is NULL
1118 }
1119 fAddr = fBitmap.getPixels();
1120 fRowBytes = fBitmap.rowBytes();
1121 }
1122 SkASSERT(fAddr); // success
1123}
1124
1125bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1126 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001127 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001128 } else {
1129 bitmap->reset();
1130 return false;
1131 }
1132}
1133
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001135void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001136 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001137 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001138 return;
1139 }
1140
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001141 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001143 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001145
1146 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001147
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001148 SkRect storage;
1149 const SkRect* bounds = NULL;
1150 if (paint && paint->canComputeFastBounds()) {
1151 bitmap.getBounds(&storage);
1152 matrix.mapRect(&storage);
1153 bounds = &paint->computeFastBounds(storage, &storage);
1154 }
1155
1156 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001157
1158 while (iter.next()) {
1159 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1160 }
1161
1162 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001163}
1164
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001165void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001166 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001167 SkPaint tmp;
1168 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001169 paint = &tmp;
1170 }
reed@google.com4b226022011-01-11 18:32:13 +00001171
reed@google.com8926b162012-03-23 15:36:36 +00001172 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001173 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001174 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001175 paint = &looper.paint();
1176 SkImageFilter* filter = paint->getImageFilter();
1177 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001178 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001179 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001180 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001181 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001182 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001183 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001184 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001185 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001186 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001187 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001188 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001189 SkPaint tmpUnfiltered(*paint);
1190 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001191 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1192 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001193 }
1194 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001195 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001196 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001197 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001198 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001199}
1200
reed41af9662015-01-05 07:49:08 -08001201void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001202 if (gTreatSpriteAsBitmap) {
1203 this->save();
1204 this->resetMatrix();
1205 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1206 this->restore();
1207 return;
1208 }
1209
danakj9881d632014-11-26 12:41:06 -08001210 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001211 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001212 return;
1213 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001214 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001215
reed@google.com8926b162012-03-23 15:36:36 +00001216 SkPaint tmp;
1217 if (NULL == paint) {
1218 paint = &tmp;
1219 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001220
reed@google.com8926b162012-03-23 15:36:36 +00001221 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001222
reed@google.com8926b162012-03-23 15:36:36 +00001223 while (iter.next()) {
1224 paint = &looper.paint();
1225 SkImageFilter* filter = paint->getImageFilter();
1226 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1227 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001228 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001229 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001230 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001231 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001232 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001233 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001234 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001235 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001236 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001237 SkPaint tmpUnfiltered(*paint);
1238 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001239 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001240 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001241 }
1242 } else {
1243 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1244 }
1245 }
1246 LOOPER_END
1247}
1248
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001250void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001251 SkMatrix m;
1252 m.setTranslate(dx, dy);
1253 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001254}
1255
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001256void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001257 SkMatrix m;
1258 m.setScale(sx, sy);
1259 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260}
1261
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001262void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001263 SkMatrix m;
1264 m.setRotate(degrees);
1265 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266}
1267
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001268void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001269 SkMatrix m;
1270 m.setSkew(sx, sy);
1271 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001272}
1273
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001274void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001275 if (matrix.isIdentity()) {
1276 return;
1277 }
1278
reed2ff1fce2014-12-11 07:07:37 -08001279 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001281 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001282 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001283
1284 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001285}
1286
reed@android.com8a1c16f2008-12-17 15:59:43 +00001287void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001288 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001290 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001291 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001292 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293}
1294
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295void SkCanvas::resetMatrix() {
1296 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001297
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298 matrix.reset();
1299 this->setMatrix(matrix);
1300}
1301
1302//////////////////////////////////////////////////////////////////////////////
1303
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001304void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001305 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001306 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1307 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001308}
1309
1310void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001311#ifdef SK_ENABLE_CLIP_QUICKREJECT
1312 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001313 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001314 return false;
1315 }
1316
reed@google.com3b3e8952012-08-16 20:53:31 +00001317 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001318 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001319 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001320
1321 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001322 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001323 }
1324 }
1325#endif
1326
reed@google.com5c3d1472011-02-22 19:12:23 +00001327 AutoValidateClip avc(this);
1328
reed@android.com8a1c16f2008-12-17 15:59:43 +00001329 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001330 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001331 if (!fAllowSoftClip) {
1332 edgeStyle = kHard_ClipEdgeStyle;
1333 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334
reed1f836ee2014-07-07 07:49:34 -07001335 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001336 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001337 // the matrix. This means we don't have to a) make a path, and b) tell
1338 // the region code to scan-convert the path, only to discover that it
1339 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341
reed1f836ee2014-07-07 07:49:34 -07001342 fMCRec->fMatrix.mapRect(&r, rect);
joshualittde358a92015-02-05 08:19:35 -08001343 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001344 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001345 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001346 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001347 // and clip against that, since it can handle any matrix. However, to
1348 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1349 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 SkPath path;
1351
1352 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001353 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354 }
1355}
1356
reed73e714e2014-09-04 09:02:23 -07001357static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1358 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001359 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001360}
1361
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001362void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001363 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001364 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001365 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001366 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1367 } else {
1368 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001369 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001370}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001371
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001372void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001373 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001374 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001375 AutoValidateClip avc(this);
1376
1377 fDeviceCMDirty = true;
1378 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001379 if (!fAllowSoftClip) {
1380 edgeStyle = kHard_ClipEdgeStyle;
1381 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001382
joshualittde358a92015-02-05 08:19:35 -08001383 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001384
1385 SkPath devPath;
1386 devPath.addRRect(transformedRRect);
1387
reed73e714e2014-09-04 09:02:23 -07001388 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001389 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001390 }
1391
1392 SkPath path;
1393 path.addRRect(rrect);
1394 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001395 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001396}
1397
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001398void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001399 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001400 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1401 SkRect r;
1402 if (!path.isInverseFillType() && path.isRect(&r)) {
1403 this->onClipRect(r, op, edgeStyle);
1404 } else {
1405 this->onClipPath(path, op, edgeStyle);
1406 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001407}
1408
1409void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001410#ifdef SK_ENABLE_CLIP_QUICKREJECT
1411 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001412 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001413 return false;
1414 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001415
reed@google.com3b3e8952012-08-16 20:53:31 +00001416 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001417 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001418 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001419
reed@google.comda17f752012-08-16 18:27:05 +00001420 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001421 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001422 }
1423 }
1424#endif
1425
reed@google.com5c3d1472011-02-22 19:12:23 +00001426 AutoValidateClip avc(this);
1427
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001429 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001430 if (!fAllowSoftClip) {
1431 edgeStyle = kHard_ClipEdgeStyle;
1432 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433
1434 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001435 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436
reed@google.comfe701122011-11-08 19:41:23 +00001437 // Check if the transfomation, or the original path itself
1438 // made us empty. Note this can also happen if we contained NaN
1439 // values. computing the bounds detects this, and will set our
1440 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1441 if (devPath.getBounds().isEmpty()) {
1442 // resetting the path will remove any NaN or other wanky values
1443 // that might upset our scan converter.
1444 devPath.reset();
1445 }
1446
reed@google.com5c3d1472011-02-22 19:12:23 +00001447 // if we called path.swap() we could avoid a deep copy of this path
joshualittde358a92015-02-05 08:19:35 -08001448 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001449
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001450 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001451 bool clipIsAA = getClipStack()->asPath(&devPath);
1452 if (clipIsAA) {
1453 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001454 }
fmalita1a481fe2015-02-04 07:39:34 -08001455
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001456 op = SkRegion::kReplace_Op;
1457 }
1458
reed73e714e2014-09-04 09:02:23 -07001459 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001460}
1461
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001462void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001463 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001464 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001465}
1466
1467void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001468 AutoValidateClip avc(this);
1469
reed@android.com8a1c16f2008-12-17 15:59:43 +00001470 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001471 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001472
reed@google.com5c3d1472011-02-22 19:12:23 +00001473 // todo: signal fClipStack that we have a region, and therefore (I guess)
1474 // we have to ignore it, and use the region directly?
joshualittde358a92015-02-05 08:19:35 -08001475 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001476
reed1f836ee2014-07-07 07:49:34 -07001477 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001478}
1479
reed@google.com819c9212011-02-23 18:56:55 +00001480#ifdef SK_DEBUG
1481void SkCanvas::validateClip() const {
1482 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001483 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001484 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001485 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001486 return;
1487 }
1488
reed@google.com819c9212011-02-23 18:56:55 +00001489 SkIRect ir;
1490 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001491 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001492
joshualittde358a92015-02-05 08:19:35 -08001493 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001494 const SkClipStack::Element* element;
1495 while ((element = iter.next()) != NULL) {
1496 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001497 case SkClipStack::Element::kRect_Type:
1498 element->getRect().round(&ir);
1499 tmpClip.op(ir, element->getOp());
1500 break;
1501 case SkClipStack::Element::kEmpty_Type:
1502 tmpClip.setEmpty();
1503 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001504 default: {
1505 SkPath path;
1506 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001507 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001508 break;
1509 }
reed@google.com819c9212011-02-23 18:56:55 +00001510 }
1511 }
reed@google.com819c9212011-02-23 18:56:55 +00001512}
1513#endif
1514
reed@google.com90c07ea2012-04-13 13:50:27 +00001515void SkCanvas::replayClips(ClipVisitor* visitor) const {
joshualittde358a92015-02-05 08:19:35 -08001516 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001517 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001518
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001519 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001520 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001521 }
1522}
1523
reed@google.com5c3d1472011-02-22 19:12:23 +00001524///////////////////////////////////////////////////////////////////////////////
1525
reed@google.com754de5f2014-02-24 19:38:20 +00001526bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001527 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001528}
1529
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001530bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001531 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001532}
1533
reed@google.com3b3e8952012-08-16 20:53:31 +00001534bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001535 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001536 return true;
1537
reed1f836ee2014-07-07 07:49:34 -07001538 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001539 return true;
1540 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001541
reed1f836ee2014-07-07 07:49:34 -07001542 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001543 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001544 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001545 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001546 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001547 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001548
reed@android.coma380ae42009-07-21 01:17:02 +00001549 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001550 // TODO: should we use | instead, or compare all 4 at once?
1551 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001552 return true;
1553 }
reed@google.comc0784db2013-12-13 21:16:12 +00001554 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001555 return true;
1556 }
1557 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001559}
1560
reed@google.com3b3e8952012-08-16 20:53:31 +00001561bool SkCanvas::quickReject(const SkPath& path) const {
1562 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001563}
1564
reed@google.com3b3e8952012-08-16 20:53:31 +00001565bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001566 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001567 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001568 return false;
1569 }
1570
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001571 SkMatrix inverse;
1572 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001573 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001574 if (bounds) {
1575 bounds->setEmpty();
1576 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001577 return false;
1578 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001579
bsalomon49f085d2014-09-05 13:34:00 -07001580 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001581 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001582 // adjust it outwards in case we are antialiasing
1583 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001584
reed@google.com8f4d2302013-12-17 16:44:46 +00001585 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1586 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001587 inverse.mapRect(bounds, r);
1588 }
1589 return true;
1590}
1591
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001592bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001593 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001594 if (clip.isEmpty()) {
1595 if (bounds) {
1596 bounds->setEmpty();
1597 }
1598 return false;
1599 }
1600
bsalomon49f085d2014-09-05 13:34:00 -07001601 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001602 *bounds = clip.getBounds();
1603 }
1604 return true;
1605}
1606
reed@android.com8a1c16f2008-12-17 15:59:43 +00001607const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001608 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001609}
1610
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001611const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001612 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001613}
1614
reed@google.com9c135db2014-03-12 18:28:35 +00001615GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1616 SkBaseDevice* dev = this->getTopDevice();
1617 return dev ? dev->accessRenderTarget() : NULL;
1618}
1619
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001620GrContext* SkCanvas::getGrContext() {
1621#if SK_SUPPORT_GPU
1622 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001623 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001624 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001625 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001626 return renderTarget->getContext();
1627 }
1628 }
1629#endif
1630
1631 return NULL;
1632
1633}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001634
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001635void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1636 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001637 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001638 if (outer.isEmpty()) {
1639 return;
1640 }
1641 if (inner.isEmpty()) {
1642 this->drawRRect(outer, paint);
1643 return;
1644 }
1645
1646 // We don't have this method (yet), but technically this is what we should
1647 // be able to assert...
1648 // SkASSERT(outer.contains(inner));
1649 //
1650 // For now at least check for containment of bounds
1651 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1652
1653 this->onDrawDRRect(outer, inner, paint);
1654}
1655
reed41af9662015-01-05 07:49:08 -08001656// These need to stop being virtual -- clients need to override the onDraw... versions
1657
1658void SkCanvas::drawPaint(const SkPaint& paint) {
1659 this->onDrawPaint(paint);
1660}
1661
1662void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1663 this->onDrawRect(r, paint);
1664}
1665
1666void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1667 this->onDrawOval(r, paint);
1668}
1669
1670void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1671 this->onDrawRRect(rrect, paint);
1672}
1673
1674void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1675 this->onDrawPoints(mode, count, pts, paint);
1676}
1677
1678void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1679 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1680 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1681 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1682 indices, indexCount, paint);
1683}
1684
1685void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1686 this->onDrawPath(path, paint);
1687}
1688
1689void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1690 this->onDrawImage(image, dx, dy, paint);
1691}
1692
1693void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1694 const SkPaint* paint) {
1695 this->onDrawImageRect(image, src, dst, paint);
1696}
1697
1698void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1699 this->onDrawBitmap(bitmap, dx, dy, paint);
1700}
1701
1702void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1703 const SkPaint* paint, DrawBitmapRectFlags flags) {
1704 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1705}
1706
1707void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1708 const SkPaint* paint) {
1709 this->onDrawBitmapNine(bitmap, center, dst, paint);
1710}
1711
1712void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
1713 this->onDrawSprite(bitmap, left, top, paint);
1714}
1715
reed@android.com8a1c16f2008-12-17 15:59:43 +00001716//////////////////////////////////////////////////////////////////////////////
1717// These are the virtual drawing methods
1718//////////////////////////////////////////////////////////////////////////////
1719
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001720void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001721 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001722 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1723 }
1724}
1725
reed41af9662015-01-05 07:49:08 -08001726void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001727 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001728 this->internalDrawPaint(paint);
1729}
1730
1731void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001732 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001733
1734 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001735 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001736 }
1737
reed@google.com4e2b3d32011-04-07 14:18:59 +00001738 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739}
1740
reed41af9662015-01-05 07:49:08 -08001741void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1742 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001743 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001744 if ((long)count <= 0) {
1745 return;
1746 }
1747
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001748 SkRect r, storage;
1749 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001750 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001751 // special-case 2 points (common for drawing a single line)
1752 if (2 == count) {
1753 r.set(pts[0], pts[1]);
1754 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001755 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001756 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001757 bounds = &paint.computeFastStrokeBounds(r, &storage);
1758 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001759 return;
1760 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001761 }
reed@google.coma584aed2012-05-16 14:06:02 +00001762
reed@android.com8a1c16f2008-12-17 15:59:43 +00001763 SkASSERT(pts != NULL);
1764
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001765 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001766
reed@android.com8a1c16f2008-12-17 15:59:43 +00001767 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001768 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001769 }
reed@google.com4b226022011-01-11 18:32:13 +00001770
reed@google.com4e2b3d32011-04-07 14:18:59 +00001771 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001772}
1773
reed41af9662015-01-05 07:49:08 -08001774void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001775 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001776 SkRect storage;
1777 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001778 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001779 bounds = &paint.computeFastBounds(r, &storage);
1780 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001781 return;
1782 }
1783 }
reed@google.com4b226022011-01-11 18:32:13 +00001784
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001785 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001786
1787 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001788 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001789 }
1790
reed@google.com4e2b3d32011-04-07 14:18:59 +00001791 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001792}
1793
reed41af9662015-01-05 07:49:08 -08001794void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001795 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001796 SkRect storage;
1797 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001798 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001799 bounds = &paint.computeFastBounds(oval, &storage);
1800 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001801 return;
1802 }
1803 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001804
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001805 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001806
1807 while (iter.next()) {
1808 iter.fDevice->drawOval(iter, oval, looper.paint());
1809 }
1810
1811 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001812}
1813
reed41af9662015-01-05 07:49:08 -08001814void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001816 SkRect storage;
1817 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001818 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001819 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1820 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001821 return;
1822 }
1823 }
1824
1825 if (rrect.isRect()) {
1826 // call the non-virtual version
1827 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001828 return;
1829 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001830 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001831 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1832 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001833 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001834
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001835 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001836
1837 while (iter.next()) {
1838 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1839 }
1840
1841 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001842}
1843
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001844void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1845 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001846 SkRect storage;
1847 const SkRect* bounds = NULL;
1848 if (paint.canComputeFastBounds()) {
1849 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1850 if (this->quickReject(*bounds)) {
1851 return;
1852 }
1853 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001854
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001855 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001856
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001857 while (iter.next()) {
1858 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1859 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001860
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001861 LOOPER_END
1862}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001863
reed41af9662015-01-05 07:49:08 -08001864void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001865 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001866 if (!path.isFinite()) {
1867 return;
1868 }
1869
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001870 SkRect storage;
1871 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001872 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001873 const SkRect& pathBounds = path.getBounds();
1874 bounds = &paint.computeFastBounds(pathBounds, &storage);
1875 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001876 return;
1877 }
1878 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001879
1880 const SkRect& r = path.getBounds();
1881 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001882 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001883 this->internalDrawPaint(paint);
1884 }
1885 return;
1886 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001887
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001888 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001889
1890 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001891 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001892 }
1893
reed@google.com4e2b3d32011-04-07 14:18:59 +00001894 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001895}
1896
reed41af9662015-01-05 07:49:08 -08001897void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001898 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reed41af9662015-01-05 07:49:08 -08001899 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001900}
1901
reed41af9662015-01-05 07:49:08 -08001902void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1903 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001904 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
piotaixr5ceff912014-09-26 07:36:26 -07001905 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001906}
1907
reed41af9662015-01-05 07:49:08 -08001908void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001909 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001910 SkDEBUGCODE(bitmap.validate();)
1911
reed@google.com3d608122011-11-21 15:16:16 +00001912 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001913 SkRect bounds = {
1914 x, y,
1915 x + SkIntToScalar(bitmap.width()),
1916 y + SkIntToScalar(bitmap.height())
1917 };
1918 if (paint) {
1919 (void)paint->computeFastBounds(bounds, &bounds);
1920 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001921 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001922 return;
1923 }
1924 }
reed@google.com4b226022011-01-11 18:32:13 +00001925
reed@android.com8a1c16f2008-12-17 15:59:43 +00001926 SkMatrix matrix;
1927 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001928 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001929}
1930
reed@google.com9987ec32011-09-07 11:57:52 +00001931// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001932void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001933 const SkRect& dst, const SkPaint* paint,
1934 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001935 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001936 return;
1937 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001938
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001939 SkRect storage;
1940 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001941 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001942 if (paint) {
1943 bounds = &paint->computeFastBounds(dst, &storage);
1944 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001945 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001946 return;
1947 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001948 }
reed@google.com3d608122011-11-21 15:16:16 +00001949
reed@google.com33535f32012-09-25 15:37:50 +00001950 SkLazyPaint lazy;
1951 if (NULL == paint) {
1952 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001953 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001954
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001955 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001956
reed@google.com33535f32012-09-25 15:37:50 +00001957 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001958 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001959 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001960
reed@google.com33535f32012-09-25 15:37:50 +00001961 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001962}
1963
reed41af9662015-01-05 07:49:08 -08001964void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1965 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001966 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001967 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001968 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001969}
1970
reed@google.com9987ec32011-09-07 11:57:52 +00001971void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1972 const SkIRect& center, const SkRect& dst,
1973 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001974 if (bitmap.drawsNothing()) {
1975 return;
1976 }
reed@google.com3d608122011-11-21 15:16:16 +00001977 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001978 SkRect storage;
1979 const SkRect* bounds = &dst;
1980 if (paint) {
1981 bounds = &paint->computeFastBounds(dst, &storage);
1982 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001983 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001984 return;
1985 }
1986 }
1987
reed@google.com9987ec32011-09-07 11:57:52 +00001988 const int32_t w = bitmap.width();
1989 const int32_t h = bitmap.height();
1990
1991 SkIRect c = center;
1992 // pin center to the bounds of the bitmap
1993 c.fLeft = SkMax32(0, center.fLeft);
1994 c.fTop = SkMax32(0, center.fTop);
1995 c.fRight = SkPin32(center.fRight, c.fLeft, w);
1996 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1997
reed@google.com71121732012-09-18 15:14:33 +00001998 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001999 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002000 };
2001 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002002 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002003 };
reed@google.com9987ec32011-09-07 11:57:52 +00002004 SkScalar dstX[4] = {
2005 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2006 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2007 };
2008 SkScalar dstY[4] = {
2009 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2010 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2011 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002012
reed@google.com9987ec32011-09-07 11:57:52 +00002013 if (dstX[1] > dstX[2]) {
2014 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2015 dstX[2] = dstX[1];
2016 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002017
reed@google.com9987ec32011-09-07 11:57:52 +00002018 if (dstY[1] > dstY[2]) {
2019 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2020 dstY[2] = dstY[1];
2021 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002022
reed@google.com9987ec32011-09-07 11:57:52 +00002023 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002024 SkRect s, d;
2025
reed@google.com9987ec32011-09-07 11:57:52 +00002026 s.fTop = srcY[y];
2027 s.fBottom = srcY[y+1];
2028 d.fTop = dstY[y];
2029 d.fBottom = dstY[y+1];
2030 for (int x = 0; x < 3; x++) {
2031 s.fLeft = srcX[x];
2032 s.fRight = srcX[x+1];
2033 d.fLeft = dstX[x];
2034 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002035 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002036 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002037 }
2038 }
2039}
2040
reed41af9662015-01-05 07:49:08 -08002041void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2042 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002043 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002044 SkDEBUGCODE(bitmap.validate();)
2045
2046 // Need a device entry-point, so gpu can use a mesh
2047 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2048}
2049
reed@google.comf67e4cf2011-03-15 20:56:58 +00002050class SkDeviceFilteredPaint {
2051public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002052 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002053 uint32_t filteredFlags = device->filterTextFlags(paint);
2054 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002055 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002056 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002057 fPaint = newPaint;
2058 } else {
2059 fPaint = &paint;
2060 }
2061 }
2062
reed@google.comf67e4cf2011-03-15 20:56:58 +00002063 const SkPaint& paint() const { return *fPaint; }
2064
2065private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002066 const SkPaint* fPaint;
2067 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002068};
2069
bungeman@google.com52c748b2011-08-22 21:30:43 +00002070void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2071 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002072 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002073 draw.fDevice->drawRect(draw, r, paint);
2074 } else {
2075 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002076 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002077 draw.fDevice->drawRect(draw, r, p);
2078 }
2079}
2080
2081void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2082 const char text[], size_t byteLength,
2083 SkScalar x, SkScalar y) {
2084 SkASSERT(byteLength == 0 || text != NULL);
2085
2086 // nothing to draw
2087 if (text == NULL || byteLength == 0 ||
2088 draw.fClip->isEmpty() ||
2089 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2090 return;
2091 }
2092
2093 SkScalar width = 0;
2094 SkPoint start;
2095
2096 start.set(0, 0); // to avoid warning
2097 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2098 SkPaint::kStrikeThruText_Flag)) {
2099 width = paint.measureText(text, byteLength);
2100
2101 SkScalar offsetX = 0;
2102 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2103 offsetX = SkScalarHalf(width);
2104 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2105 offsetX = width;
2106 }
2107 start.set(x - offsetX, y);
2108 }
2109
2110 if (0 == width) {
2111 return;
2112 }
2113
2114 uint32_t flags = paint.getFlags();
2115
2116 if (flags & (SkPaint::kUnderlineText_Flag |
2117 SkPaint::kStrikeThruText_Flag)) {
2118 SkScalar textSize = paint.getTextSize();
2119 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2120 SkRect r;
2121
2122 r.fLeft = start.fX;
2123 r.fRight = start.fX + width;
2124
2125 if (flags & SkPaint::kUnderlineText_Flag) {
2126 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2127 start.fY);
2128 r.fTop = offset;
2129 r.fBottom = offset + height;
2130 DrawRect(draw, paint, r, textSize);
2131 }
2132 if (flags & SkPaint::kStrikeThruText_Flag) {
2133 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2134 start.fY);
2135 r.fTop = offset;
2136 r.fBottom = offset + height;
2137 DrawRect(draw, paint, r, textSize);
2138 }
2139 }
2140}
2141
reed@google.come0d9ce82014-04-23 04:00:17 +00002142void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2143 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002144 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145
2146 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002147 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002148 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002149 DrawTextDecorations(iter, dfp.paint(),
2150 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151 }
2152
reed@google.com4e2b3d32011-04-07 14:18:59 +00002153 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002154}
2155
reed@google.come0d9ce82014-04-23 04:00:17 +00002156void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2157 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002158 SkPoint textOffset = SkPoint::Make(0, 0);
2159
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002160 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002161
reed@android.com8a1c16f2008-12-17 15:59:43 +00002162 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002163 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002164 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002165 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002166 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002167
reed@google.com4e2b3d32011-04-07 14:18:59 +00002168 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002169}
2170
reed@google.come0d9ce82014-04-23 04:00:17 +00002171void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2172 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002173
2174 SkPoint textOffset = SkPoint::Make(0, constY);
2175
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002176 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002177
reed@android.com8a1c16f2008-12-17 15:59:43 +00002178 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002179 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002180 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002181 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002182 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002183
reed@google.com4e2b3d32011-04-07 14:18:59 +00002184 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002185}
2186
reed@google.come0d9ce82014-04-23 04:00:17 +00002187void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2188 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002189 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002190
reed@android.com8a1c16f2008-12-17 15:59:43 +00002191 while (iter.next()) {
2192 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002193 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002194 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002195
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002196 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002197}
2198
fmalita00d5c2c2014-08-21 08:53:26 -07002199void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2200 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002201
fmalita19653d12014-10-16 11:53:30 -07002202 if (paint.canComputeFastBounds()) {
fmalita7ba7aa72014-08-29 09:46:36 -07002203 SkRect storage;
2204
2205 if (this->quickReject(paint.computeFastBounds(blob->bounds().makeOffset(x, y), &storage))) {
2206 return;
2207 }
2208 }
2209
fmalitaaa1b9122014-08-28 14:32:24 -07002210 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
fmalita00d5c2c2014-08-21 08:53:26 -07002211
fmalitaaa1b9122014-08-28 14:32:24 -07002212 while (iter.next()) {
2213 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2214 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint());
fmalita00d5c2c2014-08-21 08:53:26 -07002215 }
2216
fmalitaaa1b9122014-08-28 14:32:24 -07002217 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002218}
2219
reed@google.come0d9ce82014-04-23 04:00:17 +00002220// These will become non-virtual, so they always call the (virtual) onDraw... method
2221void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2222 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002223 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002224 this->onDrawText(text, byteLength, x, y, paint);
2225}
2226void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2227 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002228 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002229 this->onDrawPosText(text, byteLength, pos, paint);
2230}
2231void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2232 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002233 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002234 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2235}
2236void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2237 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002238 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002239 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2240}
fmalita00d5c2c2014-08-21 08:53:26 -07002241void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2242 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002243 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002244 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002245 this->onDrawTextBlob(blob, x, y, paint);
2246 }
2247}
reed@google.come0d9ce82014-04-23 04:00:17 +00002248
reed41af9662015-01-05 07:49:08 -08002249void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2250 const SkPoint verts[], const SkPoint texs[],
2251 const SkColor colors[], SkXfermode* xmode,
2252 const uint16_t indices[], int indexCount,
2253 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002254 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002255 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002256
reed@android.com8a1c16f2008-12-17 15:59:43 +00002257 while (iter.next()) {
2258 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002259 colors, xmode, indices, indexCount,
2260 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002261 }
reed@google.com4b226022011-01-11 18:32:13 +00002262
reed@google.com4e2b3d32011-04-07 14:18:59 +00002263 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002264}
2265
dandovb3c9d1c2014-08-12 08:34:29 -07002266void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2267 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002268 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002269 if (NULL == cubics) {
2270 return;
2271 }
mtklein6cfa73a2014-08-13 13:33:49 -07002272
dandovecfff212014-08-04 10:02:00 -07002273 // Since a patch is always within the convex hull of the control points, we discard it when its
2274 // bounding rectangle is completely outside the current clip.
2275 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002276 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002277 if (this->quickReject(bounds)) {
2278 return;
2279 }
mtklein6cfa73a2014-08-13 13:33:49 -07002280
dandovb3c9d1c2014-08-12 08:34:29 -07002281 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2282}
2283
2284void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2285 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2286
dandovecfff212014-08-04 10:02:00 -07002287 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002288
dandovecfff212014-08-04 10:02:00 -07002289 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002290 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002291 }
mtklein6cfa73a2014-08-13 13:33:49 -07002292
dandovecfff212014-08-04 10:02:00 -07002293 LOOPER_END
2294}
2295
reed3cb38402015-02-06 08:36:15 -08002296void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002297 if (dr && !this->quickReject(dr->getBounds())) {
2298 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002299 }
2300}
2301
reed3cb38402015-02-06 08:36:15 -08002302void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002303 dr->draw(this);
2304}
2305
reed@android.com8a1c16f2008-12-17 15:59:43 +00002306//////////////////////////////////////////////////////////////////////////////
2307// These methods are NOT virtual, and therefore must call back into virtual
2308// methods, rather than actually drawing themselves.
2309//////////////////////////////////////////////////////////////////////////////
2310
2311void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002312 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002313 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002314 SkPaint paint;
2315
2316 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002317 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002318 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002319 }
2320 this->drawPaint(paint);
2321}
2322
reed@android.com845fdac2009-06-23 03:01:32 +00002323void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002324 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002325 SkPaint paint;
2326
2327 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002328 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002329 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002330 }
2331 this->drawPaint(paint);
2332}
2333
2334void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002335 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002336 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002337
reed@android.com8a1c16f2008-12-17 15:59:43 +00002338 pt.set(x, y);
2339 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2340}
2341
2342void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002343 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002344 SkPoint pt;
2345 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002346
reed@android.com8a1c16f2008-12-17 15:59:43 +00002347 pt.set(x, y);
2348 paint.setColor(color);
2349 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2350}
2351
2352void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2353 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002354 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002355 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002356
reed@android.com8a1c16f2008-12-17 15:59:43 +00002357 pts[0].set(x0, y0);
2358 pts[1].set(x1, y1);
2359 this->drawPoints(kLines_PointMode, 2, pts, paint);
2360}
2361
2362void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2363 SkScalar right, SkScalar bottom,
2364 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002365 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002366 SkRect r;
2367
2368 r.set(left, top, right, bottom);
2369 this->drawRect(r, paint);
2370}
2371
2372void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2373 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002374 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002375 if (radius < 0) {
2376 radius = 0;
2377 }
2378
2379 SkRect r;
2380 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002381 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002382}
2383
2384void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2385 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002387 if (rx > 0 && ry > 0) {
2388 if (paint.canComputeFastBounds()) {
2389 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002390 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002391 return;
2392 }
2393 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002394 SkRRect rrect;
2395 rrect.setRectXY(r, rx, ry);
2396 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002397 } else {
2398 this->drawRect(r, paint);
2399 }
2400}
2401
reed@android.com8a1c16f2008-12-17 15:59:43 +00002402void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2403 SkScalar sweepAngle, bool useCenter,
2404 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002405 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002406 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2407 this->drawOval(oval, paint);
2408 } else {
2409 SkPath path;
2410 if (useCenter) {
2411 path.moveTo(oval.centerX(), oval.centerY());
2412 }
2413 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2414 if (useCenter) {
2415 path.close();
2416 }
2417 this->drawPath(path, paint);
2418 }
2419}
2420
2421void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2422 const SkPath& path, SkScalar hOffset,
2423 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002424 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002425 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002426
reed@android.com8a1c16f2008-12-17 15:59:43 +00002427 matrix.setTranslate(hOffset, vOffset);
2428 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2429}
2430
reed@android.comf76bacf2009-05-13 14:00:33 +00002431///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002432void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002433 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002434 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002435 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002436 }
2437}
2438
reedd5fa1a42014-08-09 11:08:05 -07002439void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002440 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002441 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002442 if (matrix && matrix->isIdentity()) {
2443 matrix = NULL;
2444 }
2445 this->onDrawPicture(picture, matrix, paint);
2446 }
2447}
robertphillips9b14f262014-06-04 05:40:44 -07002448
reedd5fa1a42014-08-09 11:08:05 -07002449void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2450 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002451 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002452 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002453 // Canvas has to first give the device the opportunity to render
2454 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002455 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002456 return; // the device has rendered the entire picture
2457 }
2458 }
2459
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002460 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002461
robertphillipsc5ba71d2014-09-04 08:42:50 -07002462 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002463}
2464
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465///////////////////////////////////////////////////////////////////////////////
2466///////////////////////////////////////////////////////////////////////////////
2467
2468SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002469 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002470
2471 SkASSERT(canvas);
2472
2473 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2474 fDone = !fImpl->next();
2475}
2476
2477SkCanvas::LayerIter::~LayerIter() {
2478 fImpl->~SkDrawIter();
2479}
2480
2481void SkCanvas::LayerIter::next() {
2482 fDone = !fImpl->next();
2483}
2484
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002485SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002486 return fImpl->getDevice();
2487}
2488
2489const SkMatrix& SkCanvas::LayerIter::matrix() const {
2490 return fImpl->getMatrix();
2491}
2492
2493const SkPaint& SkCanvas::LayerIter::paint() const {
2494 const SkPaint* paint = fImpl->getPaint();
2495 if (NULL == paint) {
2496 paint = &fDefaultPaint;
2497 }
2498 return *paint;
2499}
2500
2501const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2502int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2503int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002504
2505///////////////////////////////////////////////////////////////////////////////
2506
fmalitac3b589a2014-06-05 12:40:07 -07002507SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002508
2509///////////////////////////////////////////////////////////////////////////////
2510
2511static bool supported_for_raster_canvas(const SkImageInfo& info) {
2512 switch (info.alphaType()) {
2513 case kPremul_SkAlphaType:
2514 case kOpaque_SkAlphaType:
2515 break;
2516 default:
2517 return false;
2518 }
2519
2520 switch (info.colorType()) {
2521 case kAlpha_8_SkColorType:
2522 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002523 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002524 break;
2525 default:
2526 return false;
2527 }
2528
2529 return true;
2530}
2531
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002532SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2533 if (!supported_for_raster_canvas(info)) {
2534 return NULL;
2535 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002536
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002537 SkBitmap bitmap;
2538 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2539 return NULL;
2540 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002541 return SkNEW_ARGS(SkCanvas, (bitmap));
2542}
reedd5fa1a42014-08-09 11:08:05 -07002543
2544///////////////////////////////////////////////////////////////////////////////
2545
2546SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002547 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002548 : fCanvas(canvas)
2549 , fSaveCount(canvas->getSaveCount())
2550{
bsalomon49f085d2014-09-05 13:34:00 -07002551 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002552 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002553 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002554 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002555 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002556 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002557 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002558 canvas->save();
2559 }
mtklein6cfa73a2014-08-13 13:33:49 -07002560
bsalomon49f085d2014-09-05 13:34:00 -07002561 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002562 canvas->concat(*matrix);
2563 }
2564}
2565
2566SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2567 fCanvas->restoreToCount(fSaveCount);
2568}